diff options
191 files changed, 27529 insertions, 2275 deletions
diff --git a/arch/arm/configs/apalis_t30_defconfig b/arch/arm/configs/apalis_t30_defconfig new file mode 100644 index 000000000000..d1c2e57384a9 --- /dev/null +++ b/arch/arm/configs/apalis_t30_defconfig @@ -0,0 +1,402 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_BLK_CGROUP=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS_ALL=y +# CONFIG_ELF_CORE is not set +CONFIG_EMBEDDED=y +# CONFIG_PERF_EVENTS is not set +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_TEGRA=y +CONFIG_ARCH_TEGRA_3x_SOC=y +CONFIG_TEGRA_PCI=y +CONFIG_MACH_APALIS_T30=y +CONFIG_TEGRA_PWM=y +CONFIG_TEGRA_EMC_SCALING_ENABLE=y +CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y +CONFIG_USB_HOTPLUG=y +CONFIG_TEGRA_DYNAMIC_PWRDET=y +CONFIG_TEGRA_PLLM_RESTRICTED=y +CONFIG_TEGRA_PREINIT_CLOCKS=y +CONFIG_ARM_ERRATA_716044=y +CONFIG_ARM_ERRATA_742230=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_743622=y +CONFIG_ARM_ERRATA_751472=y +CONFIG_ARM_ERRATA_752520=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEASPM_POWERSAVE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_ANDROID_PARANOID_NETWORK is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_CAN=y +CONFIG_CAN_RAW=y +CONFIG_CAN_BCM=y +CONFIG_CAN_DEV=y +CONFIG_CAN_MCP251X=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_BLUESLEEP=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_MISC_DEVICES=y +CONFIG_UID_STAT=y +CONFIG_TEGRA_CRYPTO_DEV=y +# CONFIG_INV_SENSORS is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_ATA=y +CONFIG_SATA_AHCI_TEGRA=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_NETDEV_1000=y +CONFIG_IGB=y +# CONFIG_NETDEV_10000 is not set +# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver +CONFIG_USB_ZD1201=m +CONFIG_B43=m +CONFIG_RT2X00=y +CONFIG_RT2800USB=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_PPP=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_TOUCHSCREEN_FUSION_F0710A=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=9 +CONFIG_SERIAL_8250_RUNTIME_UARTS=9 +CONFIG_SERIAL_TEGRA=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_TEGRA=y +CONFIG_SPI=y +CONFIG_SPI_TEGRA=y +CONFIG_SPI_SPIDEV=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_SENSORS_LM95245=y +CONFIG_SENSORS_TEGRA_TSENSOR=y +CONFIG_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_TEGRA_WATCHDOG=y +CONFIG_MFD_TPS65910=y +CONFIG_MFD_STMPE=y +CONFIG_MFD_TPS6591X=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_USERSPACE_CONSUMER=y +CONFIG_REGULATOR_TPS65910=y +CONFIG_REGULATOR_TPS62360=y +CONFIG_REGULATOR_TPS6591X=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +# CONFIG_MEDIA_TUNER_SIMPLE is not set +# CONFIG_MEDIA_TUNER_TDA8290 is not set +# CONFIG_MEDIA_TUNER_TDA827X is not set +# CONFIG_MEDIA_TUNER_TDA18271 is not set +# CONFIG_MEDIA_TUNER_TDA9887 is not set +# CONFIG_MEDIA_TUNER_TEA5761 is not set +# CONFIG_MEDIA_TUNER_TEA5767 is not set +# CONFIG_MEDIA_TUNER_MT20XX is not set +# CONFIG_MEDIA_TUNER_MT2060 is not set +# CONFIG_MEDIA_TUNER_MT2266 is not set +# CONFIG_MEDIA_TUNER_MT2131 is not set +# CONFIG_MEDIA_TUNER_QT1010 is not set +# CONFIG_MEDIA_TUNER_XC2028 is not set +# CONFIG_MEDIA_TUNER_XC5000 is not set +# CONFIG_MEDIA_TUNER_XC4000 is not set +# CONFIG_MEDIA_TUNER_MXL5005S is not set +# CONFIG_MEDIA_TUNER_MXL5007T is not set +# CONFIG_MEDIA_TUNER_MC44S803 is not set +# CONFIG_MEDIA_TUNER_MAX2165 is not set +# CONFIG_MEDIA_TUNER_TDA18218 is not set +# CONFIG_MEDIA_TUNER_TDA18212 is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF2_MEMOPS=m +CONFIG_VIDEOBUF2_DMA_NVMAP=m +# CONFIG_TEGRA_AVP is not set +# CONFIG_TEGRA_MEDIASERVER is not set +CONFIG_TEGRA_NVAVP=y +# CONFIG_TEGRA_CAMERA is not set +# CONFIG_TEGRA_DTV is not set +CONFIG_VIDEO_ADV7180=m +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_MAX9526=m +CONFIG_VIDEO_TEGRA=m +CONFIG_USB_VIDEO_CLASS=y +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_VGA_ARB is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_TEGRA_GRHOST=y +CONFIG_TEGRA_DC=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_TEGRA_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_HDA_INTEL=y +CONFIG_SND_HDA_PLATFORM_DRIVER=y +CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA=y +# CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS is not set +# CONFIG_SND_HDA_CODEC_ANALOG is not set +# CONFIG_SND_HDA_CODEC_SIGMATEL is not set +# CONFIG_SND_HDA_CODEC_VIA is not set +# CONFIG_SND_HDA_CODEC_CIRRUS is not set +# CONFIG_SND_HDA_CODEC_CONEXANT is not set +# CONFIG_SND_HDA_CODEC_CA0110 is not set +# CONFIG_SND_HDA_CODEC_CA0132 is not set +# CONFIG_SND_HDA_CODEC_CMEDIA is not set +# CONFIG_SND_HDA_CODEC_SI3054 is not set +# CONFIG_SND_HDA_GENERIC is not set +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=10 +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_TEGRA=y +CONFIG_SND_SOC_TEGRA_COLIBRI_T30=y +CONFIG_HIDRAW=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_GADGET=y +CONFIG_USB_TEGRA=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_TEGRA_OTG=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_BKOPS=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PWM=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_TEGRA=y +CONFIG_RTC_DRV_TPS6591x=y +CONFIG_STAGING=y +CONFIG_IIO=y +CONFIG_STMPE_ADC=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_ROOT_NFS=y +CONFIG_CIFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=m +CONFIG_PRINTK_TIME=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_FUNCTION_TRACER=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_TEGRA_SE=y diff --git a/arch/arm/configs/colibri_pxa_defconfig b/arch/arm/configs/colibri_pxa_defconfig new file mode 100644 index 000000000000..8e8fe898bf15 --- /dev/null +++ b/arch/arm/configs/colibri_pxa_defconfig @@ -0,0 +1,340 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_BLK_CGROUP=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS_ALL=y +# CONFIG_ELF_CORE is not set +CONFIG_EMBEDDED=y +# CONFIG_PERF_EVENTS is not set +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_PXA=y +CONFIG_MACH_COLIBRI=y +CONFIG_MACH_COLIBRI300=y +CONFIG_MACH_COLIBRI320=y +CONFIG_MACH_LIMESTONE=y +CONFIG_MACH_COLIBRI_EVALBOARD=y +# CONFIG_ARM_THUMB is not set +CONFIG_PCCARD=y +CONFIG_PCMCIA_PXA2XX=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_FPE_NWFPE=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_ANDROID_PARANOID_NETWORK is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_LE_BYTE_SWAP=y +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PXA2XX=y +CONFIG_MTD_BLOCK2MTD=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_PXA3xx=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_MISC_DEVICES=y +CONFIG_UID_STAT=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +# CONFIG_SATA_PMP is not set +# CONFIG_ATA_BMDMA is not set +CONFIG_PATA_PCMCIA=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_PHYLIB=y +CONFIG_NET_ETHERNET=y +CONFIG_AX88796=y +CONFIG_AX88796C=y +CONFIG_DM9000=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver +CONFIG_USB_ZD1201=m +CONFIG_RT2X00=y +CONFIG_RT2800USB=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_PPP=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_UCB1400=y +CONFIG_TOUCHSCREEN_WM97XX=y +# CONFIG_TOUCHSCREEN_WM9705 is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_PXA=y +CONFIG_SERIAL_PXA_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_PXA=y +CONFIG_SPI=y +CONFIG_SPI_PXA2XX=y +CONFIG_SPI_SPIDEV=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_BATTERY_WM97XX=y +CONFIG_BATTERY_BQ27x00=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_SA1100_WATCHDOG=y +CONFIG_UCB1400_CORE=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_USB_VIDEO_CLASS=y +# CONFIG_RADIO_ADAPTERS is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_PXA=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_PXA2XX_AC97=y +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_PCMCIA is not set +CONFIG_SND_SOC=y +CONFIG_SND_PXA2XX_SOC=y +CONFIG_SND_SOC_COLIBRI=y +CONFIG_SND_SOC_LIMESTONE=y +CONFIG_HIDRAW=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_GADGET=y +CONFIG_USB_PXA27X=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_COLIBRI_OTG=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_BKOPS=y +CONFIG_MMC_PXA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PWM=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_PXA=y +CONFIG_STAGING=y +CONFIG_IIO=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y +CONFIG_TMPFS=y +CONFIG_YAFFS_FS=y +CONFIG_YAFFS_DISABLE_TAGS_ECC=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_ROOT_NFS=y +CONFIG_CIFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=m +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_FUNCTION_TRACER=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/arm/configs/colibri_t20_android_defconfig b/arch/arm/configs/colibri_t20_android_defconfig new file mode 100644 index 000000000000..6aa4e9ae3a1f --- /dev/null +++ b/arch/arm/configs/colibri_t20_android_defconfig @@ -0,0 +1,390 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="ramdisk.cpio" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PANIC_TIMEOUT=10 +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS_ALL=y +# CONFIG_ELF_CORE is not set +CONFIG_ASHMEM=y +CONFIG_EMBEDDED=y +# CONFIG_PERF_EVENTS is not set +# CONFIG_PCI_QUIRKS is not set +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_TEGRA=y +CONFIG_MACH_COLIBRI_T20=y +CONFIG_TEGRA_PWM=y +CONFIG_TEGRA_EMC_SCALING_ENABLE=y +CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y +CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND=y +CONFIG_USB_HOTPLUG=y +CONFIG_TEGRA_PREINIT_CLOCKS=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_751472=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_USE_OF=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_WAKELOCK=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_BLUESLEEP=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_RFKILL=y +CONFIG_RFKILL_GPIO=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_PROC_DEVICETREE=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND_TEGRA=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_MISC_DEVICES=y +CONFIG_UID_STAT=y +# CONFIG_BCM4329_RFKILL is not set +CONFIG_TEGRA_CRYPTO_DEV=y +# CONFIG_INV_SENSORS is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver +CONFIG_USB_ZD1201=m +CONFIG_RT2X00=y +CONFIG_RT2800USB=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_ARMLINUX is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_PPP=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_WM97XX=y +# CONFIG_TOUCHSCREEN_WM9705 is not set +# CONFIG_TOUCHSCREEN_WM9713 is not set +CONFIG_TOUCHSCREEN_FUSION_F0710A=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=9 +CONFIG_SERIAL_8250_RUNTIME_UARTS=9 +CONFIG_SERIAL_TEGRA=y +# CONFIG_HW_RANDOM is not set +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_TEGRA=y +CONFIG_SPI=y +CONFIG_SPI_TEGRA=y +CONFIG_SPI_SPIDEV=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_BATTERY_WM97XX=y +CONFIG_SENSORS_LM95245=y +CONFIG_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_TEGRA_WATCHDOG=y +CONFIG_MFD_TPS6586X=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_TPS6586X=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +# CONFIG_TEGRA_CAMERA is not set +# CONFIG_TEGRA_DTV is not set +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_USB_VIDEO_CLASS=y +# CONFIG_USB_GSPCA is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_VGA_ARB is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_TEGRA_GRHOST=y +CONFIG_TEGRA_DC=y +CONFIG_TEGRA_NVHDCP=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_TEGRA_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_PCI is not set +CONFIG_SND_SOC=y +CONFIG_SND_SOC_TEGRA=y +CONFIG_SND_SOC_TEGRA_COLIBRI_T20=y +CONFIG_HIDRAW=y +CONFIG_USB_HIDDEV=y +CONFIG_HID_SONY=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_TEGRA=y +CONFIG_USB_ACM=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_SERIAL_OPTION=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_TEGRA=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_COLIBRI_OTG=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PWM=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_TPS6586X=y +CONFIG_RTC_DRV_TEGRA=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_IIO=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_YAFFS_FS=y +CONFIG_YAFFS_DISABLE_TAGS_ECC=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_ROOT_NFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_FS=y +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_FUNCTION_TRACER=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_TEGRA_AES=y diff --git a/arch/arm/configs/colibri_t20_defconfig b/arch/arm/configs/colibri_t20_defconfig new file mode 100644 index 000000000000..8fe150767638 --- /dev/null +++ b/arch/arm/configs/colibri_t20_defconfig @@ -0,0 +1,345 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_BLK_CGROUP=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS_ALL=y +# CONFIG_ELF_CORE is not set +CONFIG_EMBEDDED=y +# CONFIG_PERF_EVENTS is not set +# CONFIG_PCI_QUIRKS is not set +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_TEGRA=y +CONFIG_MACH_COLIBRI_T20=y +CONFIG_TEGRA_PWM=y +CONFIG_TEGRA_EMC_SCALING_ENABLE=y +CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y +CONFIG_USB_HOTPLUG=y +CONFIG_TEGRA_PREINIT_CLOCKS=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_751472=y +CONFIG_ARM_ERRATA_752520=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_ANDROID_PARANOID_NETWORK is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_BLUESLEEP=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND_TEGRA=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_MISC_DEVICES=y +CONFIG_UID_STAT=y +CONFIG_TEGRA_CRYPTO_DEV=y +# CONFIG_INV_SENSORS is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver +CONFIG_USB_ZD1201=m +CONFIG_RT2X00=y +CONFIG_RT2800USB=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_PPP=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_WM97XX=y +# CONFIG_TOUCHSCREEN_WM9705 is not set +# CONFIG_TOUCHSCREEN_WM9713 is not set +CONFIG_TOUCHSCREEN_FUSION_F0710A=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=9 +CONFIG_SERIAL_8250_RUNTIME_UARTS=9 +CONFIG_SERIAL_TEGRA=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_TEGRA=y +CONFIG_SPI=y +CONFIG_SPI_TEGRA=y +CONFIG_SPI_SPIDEV=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_BATTERY_WM97XX=y +CONFIG_SENSORS_LM95245=y +CONFIG_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_TEGRA_WATCHDOG=y +CONFIG_MFD_TPS6586X=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_USERSPACE_CONSUMER=y +CONFIG_REGULATOR_TPS6586X=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +# CONFIG_TEGRA_CAMERA is not set +# CONFIG_TEGRA_DTV is not set +CONFIG_USB_VIDEO_CLASS=y +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_VGA_ARB is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_TEGRA_GRHOST=y +CONFIG_TEGRA_DC=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_TEGRA_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_PCI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_TEGRA=y +CONFIG_SND_SOC_TEGRA_COLIBRI_T20=y +CONFIG_HIDRAW=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_TEGRA=y +CONFIG_USB_ACM=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_GADGET=y +CONFIG_USB_TEGRA=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_COLIBRI_OTG=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_BKOPS=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PWM=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_TPS6586X=y +CONFIG_RTC_DRV_TEGRA=y +CONFIG_STAGING=y +CONFIG_IIO=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y +CONFIG_TMPFS=y +CONFIG_YAFFS_FS=y +CONFIG_YAFFS_DISABLE_TAGS_ECC=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_ROOT_NFS=y +CONFIG_CIFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=m +CONFIG_PRINTK_TIME=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_FUNCTION_TRACER=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_TEGRA_AES=y diff --git a/arch/arm/configs/colibri_t30_android_defconfig b/arch/arm/configs/colibri_t30_android_defconfig new file mode 100644 index 000000000000..cec9d12b2c3b --- /dev/null +++ b/arch/arm/configs/colibri_t30_android_defconfig @@ -0,0 +1,440 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="ramdisk.cpio" +CONFIG_PANIC_TIMEOUT=10 +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_ELF_CORE is not set +CONFIG_ASHMEM=y +CONFIG_EMBEDDED=y +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_TEGRA=y +CONFIG_ARCH_TEGRA_3x_SOC=y +CONFIG_TEGRA_PCI=y +CONFIG_MACH_COLIBRI_T30=y +CONFIG_TEGRA_PWM=y +CONFIG_TEGRA_EMC_SCALING_ENABLE=y +CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y +CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND=y +CONFIG_USB_HOTPLUG=y +CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ=800 +CONFIG_TEGRA_DYNAMIC_PWRDET=y +CONFIG_TEGRA_PLLM_RESTRICTED=y +CONFIG_TEGRA_PREINIT_CLOCKS=y +CONFIG_TEGRA_LP1_950=y +CONFIG_ARM_ERRATA_742230=y +CONFIG_ARM_ERRATA_743622=y +CONFIG_ARM_ERRATA_751472=y +CONFIG_ARM_ERRATA_752520=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEASPM_POWERSAVE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y +CONFIG_USE_OF=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_WAKELOCK=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_TARGET_LOG=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_BLUESLEEP=y +CONFIG_CFG80211=m +CONFIG_NL80211_TESTMODE=y +CONFIG_LIB80211=m +CONFIG_MAC80211=m +CONFIG_RFKILL=y +CONFIG_RFKILL_GPIO=y +CONFIG_CAIF=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_PROC_DEVICETREE=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_MISC_DEVICES=y +CONFIG_UID_STAT=y +CONFIG_TEGRA_CRYPTO_DEV=y +# CONFIG_INV_SENSORS is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +CONFIG_BCM4329=m +CONFIG_BCM4329_FIRST_SCAN=y +CONFIG_BCM4329_FW_PATH="/system/vendor/firmware/fw_bcm4329.bin" +CONFIG_BCM4329_NVRAM_PATH="/system/etc/nvram_4329.txt" +CONFIG_BCM4329_WIFI_CONTROL_FUNC=y +CONFIG_BCM4329_HW_OOB=y +CONFIG_BCM4329_OOB_INTR_ONLY=y +CONFIG_BCM4329_CSCAN_ENABLE=y +CONFIG_BCMDHD=m +CONFIG_DHD_ENABLE_P2P=y +CONFIG_BCMDHD_CFG80211=y +CONFIG_BCMDHD_WIFI_CONTROL_FUNC=y +CONFIG_BCMDHD_HW_OOB=y +CONFIG_BCMDHD_CSCAN_ENABLE=y +CONFIG_BCMDHD_INSMOD_NO_FW_LOAD=y +# CONFIG_BCMDHD_CUSTOM_REGULATORY_DOMAIN is not set +CONFIG_SD8797=m +CONFIG_WL12XX_MENU=m +CONFIG_WL12XX=m +CONFIG_WL12XX_SDIO=m +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_ARMLINUX is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_USB_NET_RAW_IP=m +CONFIG_PPP=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_TOUCHSCREEN_FUSION_F0710A=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_TEGRA=y +# CONFIG_HW_RANDOM is not set +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_TEGRA=y +CONFIG_SPI=y +CONFIG_SPI_TEGRA=y +CONFIG_SPI_SLAVE_TEGRA=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_SENSORS_LM95245=y +CONFIG_SENSORS_TEGRA_TSENSOR=y +CONFIG_THERMAL=y +CONFIG_MFD_TPS65910=y +CONFIG_MFD_STMPE=y +CONFIG_MFD_TPS6591X=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_USERSPACE_CONSUMER=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_TPS65910=y +CONFIG_REGULATOR_TPS62360=y +CONFIG_REGULATOR_TPS6591X=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_TEGRA_AVP is not set +# CONFIG_TEGRA_MEDIASERVER is not set +CONFIG_TEGRA_NVAVP=y +# CONFIG_TEGRA_CAMERA is not set +CONFIG_TEGRA_NVAVP_AUDIO=y +CONFIG_VIDEO_OV5650=y +CONFIG_VIDEO_OV5640=y +CONFIG_VIDEO_OV9726=y +CONFIG_VIDEO_OV2710=y +CONFIG_VIDEO_AR0832=y +CONFIG_TORCH_SSL3250A=y +CONFIG_TORCH_TPS61050=y +CONFIG_VIDEO_SH532U=y +CONFIG_VIDEO_AD5816=y +CONFIG_USB_VIDEO_CLASS=y +# CONFIG_USB_GSPCA is not set +# CONFIG_RADIO_ADAPTERS is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_TEGRA_GRHOST=y +CONFIG_TEGRA_DC=y +CONFIG_TEGRA_DSI=y +CONFIG_TEGRA_NVHDCP=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_TEGRA_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_HDA_INTEL=y +CONFIG_SND_HDA_PLATFORM_DRIVER=y +CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA=y +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=10 +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_TEGRA=y +CONFIG_SND_SOC_TEGRA_COLIBRI_T30=y +CONFIG_HIDRAW=y +CONFIG_USB_HIDDEV=y +CONFIG_HID_SONY=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_SERIAL_OPTION=y +CONFIG_USB_SERIAL_BASEBAND=m +CONFIG_USB_GADGET=y +CONFIG_USB_TEGRA=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_COLIBRI_OTG=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_TPS6591x=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_IIO=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_ROOT_NFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_SECTION_MISMATCH=y +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAILSLAB=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_FUNCTION_TRACER=y +# CONFIG_FUNCTION_GRAPH_TRACER is not set +CONFIG_TRACEDUMP=y +CONFIG_TRACEDUMP_PROCFS=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_TEGRA_SE=y diff --git a/arch/arm/configs/colibri_t30_defconfig b/arch/arm/configs/colibri_t30_defconfig new file mode 100644 index 000000000000..5fd0bdc80b99 --- /dev/null +++ b/arch/arm/configs/colibri_t30_defconfig @@ -0,0 +1,344 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_BLK_CGROUP=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS_ALL=y +# CONFIG_ELF_CORE is not set +CONFIG_EMBEDDED=y +# CONFIG_PERF_EVENTS is not set +# CONFIG_PCI_QUIRKS is not set +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_TEGRA=y +CONFIG_ARCH_TEGRA_3x_SOC=y +CONFIG_MACH_COLIBRI_T30=y +CONFIG_TEGRA_PWM=y +CONFIG_TEGRA_EMC_SCALING_ENABLE=y +CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y +CONFIG_USB_HOTPLUG=y +CONFIG_TEGRA_DYNAMIC_PWRDET=y +CONFIG_TEGRA_PLLM_RESTRICTED=y +CONFIG_TEGRA_PREINIT_CLOCKS=y +CONFIG_ARM_ERRATA_742230=y +CONFIG_ARM_ERRATA_743622=y +CONFIG_ARM_ERRATA_751472=y +CONFIG_ARM_ERRATA_752520=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_PM_RUNTIME=y +CONFIG_SUSPEND_TIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_ANDROID_PARANOID_NETWORK is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +CONFIG_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_BLUESLEEP=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_MISC_DEVICES=y +CONFIG_UID_STAT=y +CONFIG_TEGRA_CRYPTO_DEV=y +# CONFIG_INV_SENSORS is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver +CONFIG_USB_ZD1201=m +CONFIG_RT2X00=y +CONFIG_RT2800USB=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_PPP=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_TOUCHSCREEN_FUSION_F0710A=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=9 +CONFIG_SERIAL_8250_RUNTIME_UARTS=9 +CONFIG_SERIAL_TEGRA=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_TEGRA=y +CONFIG_SPI=y +CONFIG_SPI_TEGRA=y +CONFIG_SPI_SPIDEV=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_SENSORS_LM95245=y +CONFIG_SENSORS_TEGRA_TSENSOR=y +CONFIG_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_TEGRA_WATCHDOG=y +CONFIG_MFD_TPS65910=y +CONFIG_MFD_STMPE=y +CONFIG_MFD_TPS6591X=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_USERSPACE_CONSUMER=y +CONFIG_REGULATOR_TPS65910=y +CONFIG_REGULATOR_TPS62360=y +CONFIG_REGULATOR_TPS6591X=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +# CONFIG_TEGRA_AVP is not set +# CONFIG_TEGRA_MEDIASERVER is not set +CONFIG_TEGRA_NVAVP=y +# CONFIG_TEGRA_CAMERA is not set +# CONFIG_TEGRA_DTV is not set +CONFIG_USB_VIDEO_CLASS=y +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_VGA_ARB is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_TEGRA_GRHOST=y +CONFIG_TEGRA_DC=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_TEGRA_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_PCI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_TEGRA=y +CONFIG_SND_SOC_TEGRA_COLIBRI_T30=y +CONFIG_HIDRAW=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_WDM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_GADGET=y +CONFIG_USB_TEGRA=y +CONFIG_USB_G_ANDROID=y +CONFIG_USB_COLIBRI_OTG=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_BKOPS=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PWM=y +CONFIG_SWITCH=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_TEGRA=y +CONFIG_RTC_DRV_TPS6591x=y +CONFIG_STAGING=y +CONFIG_IIO=y +CONFIG_STMPE_ADC=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_CUSE=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=m +CONFIG_NTFS_RW=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_ROOT_NFS=y +CONFIG_CIFS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_EFI_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=m +CONFIG_PRINTK_TIME=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_VM=y +CONFIG_FUNCTION_TRACER=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_TEGRA_SE=y diff --git a/arch/arm/include/asm/exception.h b/arch/arm/include/asm/exception.h new file mode 100644 index 000000000000..5abaf5bbd985 --- /dev/null +++ b/arch/arm/include/asm/exception.h @@ -0,0 +1,19 @@ +/* + * Annotations for marking C functions as exception handlers. + * + * These should only be used for C functions that are called from the low + * level exception entry code and not any intervening C code. + */ +#ifndef __ASM_ARM_EXCEPTION_H +#define __ASM_ARM_EXCEPTION_H + +#include <linux/ftrace.h> + +#define __exception __attribute__((section(".exception.text"))) +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +#define __exception_irq_entry __irq_entry +#else +#define __exception_irq_entry __exception +#endif + +#endif /* __ASM_ARM_EXCEPTION_H */ diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 832888d0c20c..ed6b0499a106 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -62,13 +62,6 @@ #include <asm/outercache.h> -#define __exception __attribute__((section(".exception.text"))) -#ifdef CONFIG_FUNCTION_GRAPH_TRACER -#define __exception_irq_entry __irq_entry -#else -#define __exception_irq_entry __exception -#endif - struct thread_info; struct task_struct; diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index de3dcab8610b..53919b230e8b 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -35,8 +35,8 @@ #include <linux/list.h> #include <linux/kallsyms.h> #include <linux/proc_fs.h> -#include <linux/ftrace.h> +#include <asm/exception.h> #include <asm/system.h> #include <asm/mach/arch.h> #include <asm/mach/irq.h> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 016473c1d794..45664df79f05 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -16,7 +16,6 @@ #include <linux/cache.h> #include <linux/profile.h> #include <linux/errno.h> -#include <linux/ftrace.h> #include <linux/mm.h> #include <linux/err.h> #include <linux/cpu.h> @@ -31,6 +30,7 @@ #include <asm/cacheflush.h> #include <asm/cpu.h> #include <asm/cputype.h> +#include <asm/exception.h> #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 2534d2a1a164..6a7e9ee75290 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -30,6 +30,7 @@ #include <linux/atomic.h> #include <asm/cacheflush.h> +#include <asm/exception.h> #include <asm/system.h> #include <asm/unistd.h> #include <asm/traps.h> diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index cd19309fd3b8..95ed956cf123 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -235,23 +235,25 @@ endchoice config MACH_COLIBRI bool "Toradex Colibri PXA270" select PXA27x + select HAVE_PWM config MACH_COLIBRI_PXA270_INCOME bool "Income s.r.o. PXA270 SBC" depends on MACH_COLIBRI select PXA27x - select HAVE_PWM config MACH_COLIBRI300 bool "Toradex Colibri PXA300/310" select PXA3xx select CPU_PXA300 select CPU_PXA310 + select HAVE_PWM config MACH_COLIBRI320 bool "Toradex Colibri PXA320" select PXA3xx select CPU_PXA320 + select HAVE_PWM config MACH_COLIBRI_EVALBOARD bool "Toradex Colibri Evaluation Carrier Board support" diff --git a/arch/arm/mach-pxa/colibri-evalboard.c b/arch/arm/mach-pxa/colibri-evalboard.c index d28e802e2448..64733482f25c 100644 --- a/arch/arm/mach-pxa/colibri-evalboard.c +++ b/arch/arm/mach-pxa/colibri-evalboard.c @@ -46,7 +46,7 @@ static void __init colibri_mmc_init(void) if (machine_is_colibri()) /* PXA270 Colibri */ colibri_mci_platform_data.gpio_card_detect = GPIO0_COLIBRI_PXA270_SD_DETECT; - if (machine_is_colibri300()) /* PXA300 Colibri */ + else if (machine_is_colibri300()) /* PXA300 Colibri */ colibri_mci_platform_data.gpio_card_detect = GPIO13_COLIBRI_PXA300_SD_DETECT; else /* PXA320 Colibri */ diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index b09e848eb6c6..ca6075717824 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -19,6 +19,8 @@ #include <linux/io.h> #include <linux/irq.h> +#include <asm/exception.h> + #include <mach/hardware.h> #include <mach/irqs.h> #include <mach/gpio.h> diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 8db76065ea6d..6ca839316e1a 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -29,9 +29,6 @@ config ARCH_TEGRA_2x_SOC select USB_ULPI if USB_SUPPORT select USB_ULPI_VIEWPORT if USB_SUPPORT select ARM_ERRATA_742230 if SMP - select USB_ARCH_HAS_EHCI if USB_SUPPORT - select USB_ULPI if USB_SUPPORT - select USB_ULPI_VIEWPORT if USB_SUPPORT select ARCH_SUPPORTS_MSI if TEGRA_PCI select PCI_MSI if TEGRA_PCI select CPA @@ -101,6 +98,12 @@ config TEGRA_IRDA comment "Tegra board type" +config MACH_COLIBRI_T20 + bool "Toradex Colibri T20 module" + depends on ARCH_TEGRA_2x_SOC + help + Support for Toradex Colibri T20 module on Iris carrier board + config MACH_HARMONY bool "Harmony board" depends on ARCH_TEGRA_2x_SOC @@ -166,6 +169,13 @@ config MACH_WHISTLER help Support for NVIDIA Whistler development platform +config MACH_APALIS_T30 + bool "Toradex Apalis T30 module" + depends on ARCH_TEGRA_3x_SOC + help + Support for Toradex Apalis T30 module on Apalis evaluation carrier + board + config MACH_ARUBA bool "Aruba board" depends on ARCH_TEGRA_3x_SOC @@ -183,6 +193,12 @@ config MACH_CARDHU help Support for NVIDIA Cardhu development platform +config MACH_COLIBRI_T30 + bool "Toradex Colibri T30 module" + depends on ARCH_TEGRA_3x_SOC + help + Support for Toradex Colibri T30 module on Iris carrier board + config MACH_P1852 bool "P1852 board" depends on ARCH_TEGRA_3x_SOC diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 85e1964a2284..4a74b6481a65 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -116,6 +116,13 @@ obj-$(CONFIG_SENSORS_TEGRA_TSENSOR) += tegra3_tsensor.o obj-$(CONFIG_TEGRA_DYNAMIC_PWRDET) += powerdetect.o obj-$(CONFIG_TEGRA_USB_MODEM_POWER) += tegra_usb_modem_power.o obj-$(CONFIG_TEGRA_PCI) += pcie.o + +obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20.o +obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20-memory.o +obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20-panel.o +obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20-pinmux.o +obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20-power.o + obj-${CONFIG_MACH_HARMONY} += board-harmony.o obj-${CONFIG_MACH_HARMONY} += board-harmony-kbc.o obj-${CONFIG_MACH_HARMONY} += board-harmony-panel.o @@ -162,6 +169,12 @@ obj-${CONFIG_MACH_WHISTLER} += board-whistler-kbc.o obj-${CONFIG_MACH_WHISTLER} += board-whistler-baseband.o obj-${CONFIG_MACH_WHISTLER} += board-whistler-memory.o +obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30.o +obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30-memory.o +obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30-panel.o +obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30-pinmux.o +obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30-power.o + obj-${CONFIG_MACH_CARDHU} += board-cardhu.o obj-${CONFIG_MACH_CARDHU} += board-cardhu-kbc.o obj-${CONFIG_MACH_CARDHU} += board-cardhu-irda.o @@ -175,6 +188,12 @@ obj-${CONFIG_MACH_CARDHU} += board-cardhu-sensors.o obj-${CONFIG_MACH_CARDHU} += board-cardhu-memory.o obj-${CONFIG_MACH_CARDHU} += board-cardhu-powermon.o +obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30.o +obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30-memory.o +obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30-panel.o +obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30-pinmux.o +obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30-power.o + obj-${CONFIG_MACH_KAI} += board-touch-kai-synaptics-spi.o obj-y += board-touch-raydium_spi.o diff --git a/arch/arm/mach-tegra/asm_macros.h b/arch/arm/mach-tegra/asm_macros.h index 2463d797ce39..1926418957ba 100644 --- a/arch/arm/mach-tegra/asm_macros.h +++ b/arch/arm/mach-tegra/asm_macros.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/asm_macros.h + * arch/arm/mach-tegra/asm_macros.h * * Copyright (C) 2011 NVIDIA Corporation * diff --git a/arch/arm/mach-tegra/board-apalis_t30-memory.c b/arch/arm/mach-tegra/board-apalis_t30-memory.c new file mode 100644 index 000000000000..ee3d3858e285 --- /dev/null +++ b/arch/arm/mach-tegra/board-apalis_t30-memory.c @@ -0,0 +1,2091 @@ +/* + * Copyright (C) 2013 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/kernel.h> +#include <linux/init.h> + +#include "board.h" +#include "board-apalis_t30.h" +#include "tegra3_emc.h" +#include "fuse.h" + +#if 0 +static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = { + { + 0x32, /* Rev 3.2 */ + 25500, /* SDRAM frequency */ + { + 0x00000001, /* EMC_RC */ + 0x00000003, /* EMC_RFC */ + 0x00000000, /* EMC_RAS */ + 0x00000000, /* EMC_RP */ + 0x00000002, /* EMC_R2W */ + 0x0000000a, /* EMC_W2R */ + 0x00000003, /* EMC_R2P */ + 0x0000000b, /* EMC_W2P */ + 0x00000000, /* EMC_RD_RCD */ + 0x00000000, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000005, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000007, /* EMC_QSAFE */ + 0x0000000c, /* EMC_RDV */ + 0x000000bd, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x0000002f, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000002, /* EMC_PDEX2WR */ + 0x00000002, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000007, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x00000005, /* EMC_TXSR */ + 0x00000005, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x00000001, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x000000c3, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00006288, /* EMC_FBIO_CFG5 */ + 0x007800a4, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQ0 */ + 0x00080000, /* EMC_DLL_XFORM_DQ1 */ + 0x00080000, /* EMC_DLL_XFORM_DQ2 */ + 0x00080000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800211c, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77ffc084, /* EMC_XM2CLKPADCTRL */ + 0x01f1f108, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x08000168, /* EMC_XM2QUSEPADCTRL */ + 0x08000000, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00000000, /* EMC_ZCAL_INTERVAL */ + 0x00000040, /* EMC_ZCAL_WAIT_CNT */ + 0x000c000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x80000280, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00030003, /* MC_EMEM_ARB_CFG */ + 0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06020102, /* MC_EMEM_ARB_DA_TURNS */ + 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */ + 0x74430303, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xd8000000, /* EMC_FBIO_SPARE */ + 0xff00ff00, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80001221, /* Mode Register 0 */ + 0x80100003, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000001, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 51000, /* SDRAM frequency */ + { + 0x00000002, /* EMC_RC */ + 0x00000008, /* EMC_RFC */ + 0x00000001, /* EMC_RAS */ + 0x00000000, /* EMC_RP */ + 0x00000002, /* EMC_R2W */ + 0x0000000a, /* EMC_W2R */ + 0x00000003, /* EMC_R2P */ + 0x0000000b, /* EMC_W2P */ + 0x00000000, /* EMC_RD_RCD */ + 0x00000000, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000005, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000007, /* EMC_QSAFE */ + 0x0000000c, /* EMC_RDV */ + 0x00000181, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x00000060, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000002, /* EMC_PDEX2WR */ + 0x00000002, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000007, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x00000009, /* EMC_TXSR */ + 0x00000009, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x00000002, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x0000018e, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00006288, /* EMC_FBIO_CFG5 */ + 0x007800a4, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQ0 */ + 0x00080000, /* EMC_DLL_XFORM_DQ1 */ + 0x00080000, /* EMC_DLL_XFORM_DQ2 */ + 0x00080000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800211c, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77ffc084, /* EMC_XM2CLKPADCTRL */ + 0x01f1f108, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x08000168, /* EMC_XM2QUSEPADCTRL */ + 0x08000000, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00000000, /* EMC_ZCAL_INTERVAL */ + 0x00000040, /* EMC_ZCAL_WAIT_CNT */ + 0x000c000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00010003, /* MC_EMEM_ARB_CFG */ + 0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06020102, /* MC_EMEM_ARB_DA_TURNS */ + 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */ + 0x73430303, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xd8000000, /* EMC_FBIO_SPARE */ + 0xff00ff00, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80001221, /* Mode Register 0 */ + 0x80100003, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000001, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 102000, /* SDRAM frequency */ + { + 0x00000004, /* EMC_RC */ + 0x00000010, /* EMC_RFC */ + 0x00000003, /* EMC_RAS */ + 0x00000001, /* EMC_RP */ + 0x00000002, /* EMC_R2W */ + 0x0000000a, /* EMC_W2R */ + 0x00000003, /* EMC_R2P */ + 0x0000000b, /* EMC_W2P */ + 0x00000001, /* EMC_RD_RCD */ + 0x00000001, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000005, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000007, /* EMC_QSAFE */ + 0x0000000c, /* EMC_RDV */ + 0x00000303, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x000000c0, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000002, /* EMC_PDEX2WR */ + 0x00000002, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000007, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x00000012, /* EMC_TXSR */ + 0x00000012, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x00000004, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x0000031c, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00006288, /* EMC_FBIO_CFG5 */ + 0x007800a4, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQ0 */ + 0x00080000, /* EMC_DLL_XFORM_DQ1 */ + 0x00080000, /* EMC_DLL_XFORM_DQ2 */ + 0x00080000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800211c, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77ffc084, /* EMC_XM2CLKPADCTRL */ + 0x01f1f108, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x08000168, /* EMC_XM2QUSEPADCTRL */ + 0x08000000, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00000000, /* EMC_ZCAL_INTERVAL */ + 0x00000040, /* EMC_ZCAL_WAIT_CNT */ + 0x000c000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x80000713, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000003, /* MC_EMEM_ARB_CFG */ + 0xc0000018, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06020102, /* MC_EMEM_ARB_DA_TURNS */ + 0x000a0403, /* MC_EMEM_ARB_DA_COVERS */ + 0x72830504, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xd8000000, /* EMC_FBIO_SPARE */ + 0xff00ff00, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80001221, /* Mode Register 0 */ + 0x80100003, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000001, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 204000, /* SDRAM frequency */ + { + 0x00000009, /* EMC_RC */ + 0x00000020, /* EMC_RFC */ + 0x00000007, /* EMC_RAS */ + 0x00000002, /* EMC_RP */ + 0x00000002, /* EMC_R2W */ + 0x0000000a, /* EMC_W2R */ + 0x00000005, /* EMC_R2P */ + 0x0000000b, /* EMC_W2P */ + 0x00000002, /* EMC_RD_RCD */ + 0x00000002, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000005, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000009, /* EMC_QSAFE */ + 0x0000000b, /* EMC_RDV */ + 0x00000607, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x00000181, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000002, /* EMC_PDEX2WR */ + 0x00000002, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000007, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x00000023, /* EMC_TXSR */ + 0x00000023, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x00000007, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x00000638, /* EMC_TREFBW */ + 0x00000006, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00004288, /* EMC_FBIO_CFG5 */ + 0x004400a4, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQ0 */ + 0x00080000, /* EMC_DLL_XFORM_DQ1 */ + 0x00080000, /* EMC_DLL_XFORM_DQ2 */ + 0x00080000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800211c, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f108, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x08000168, /* EMC_XM2QUSEPADCTRL */ + 0x08000000, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x000c000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x80000d22, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000006, /* MC_EMEM_ARB_CFG */ + 0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06020102, /* MC_EMEM_ARB_DA_TURNS */ + 0x000a0505, /* MC_EMEM_ARB_DA_COVERS */ + 0x72440a06, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff00, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80001221, /* Mode Register 0 */ + 0x80100003, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000001, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 375000, /* SDRAM frequency */ + { + 0x00000011, /* EMC_RC */ + 0x0000003a, /* EMC_RFC */ + 0x0000000c, /* EMC_RAS */ + 0x00000004, /* EMC_RP */ + 0x00000003, /* EMC_R2W */ + 0x00000008, /* EMC_W2R */ + 0x00000002, /* EMC_R2P */ + 0x0000000a, /* EMC_W2P */ + 0x00000004, /* EMC_RD_RCD */ + 0x00000004, /* EMC_WR_RCD */ + 0x00000002, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000004, /* EMC_WDV */ + 0x00000006, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000008, /* EMC_QSAFE */ + 0x0000000d, /* EMC_RDV */ + 0x00000b2d, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x000002cb, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000008, /* EMC_PDEX2WR */ + 0x00000008, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000007, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x00000040, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000009, /* EMC_TCKE */ + 0x0000000c, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x00000b6d, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000006, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00007088, /* EMC_FBIO_CFG5 */ + 0x00200084, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x0003c000, /* EMC_DLL_XFORM_DQS0 */ + 0x0003c000, /* EMC_DLL_XFORM_DQS1 */ + 0x0003c000, /* EMC_DLL_XFORM_DQS2 */ + 0x0003c000, /* EMC_DLL_XFORM_DQS3 */ + 0x0003c000, /* EMC_DLL_XFORM_DQS4 */ + 0x0003c000, /* EMC_DLL_XFORM_DQS5 */ + 0x0003c000, /* EMC_DLL_XFORM_DQS6 */ + 0x0003c000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00040000, /* EMC_DLL_XFORM_DQ0 */ + 0x00040000, /* EMC_DLL_XFORM_DQ1 */ + 0x00040000, /* EMC_DLL_XFORM_DQ2 */ + 0x00040000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800013d, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f508, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x08000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x0184000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x8000174b, /* EMC_DYN_SELF_REF_CONTROL */ + 0x0000000b, /* MC_EMEM_ARB_CFG */ + 0xc0000044, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000009, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000005, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06030202, /* MC_EMEM_ARB_DA_TURNS */ + 0x000d0709, /* MC_EMEM_ARB_DA_COVERS */ + 0x75c6110a, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0x58000000, /* EMC_FBIO_SPARE */ + 0xff00ff88, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80000521, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200000, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 400000, /* SDRAM frequency */ + { + 0x00000012, /* EMC_RC */ + 0x00000040, /* EMC_RFC */ + 0x0000000d, /* EMC_RAS */ + 0x00000004, /* EMC_RP */ + 0x00000002, /* EMC_R2W */ + 0x00000009, /* EMC_W2R */ + 0x00000002, /* EMC_R2P */ + 0x0000000c, /* EMC_W2P */ + 0x00000004, /* EMC_RD_RCD */ + 0x00000004, /* EMC_WR_RCD */ + 0x00000002, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000007, /* EMC_QUSE */ + 0x00000005, /* EMC_QRST */ + 0x00000008, /* EMC_QSAFE */ + 0x0000000e, /* EMC_RDV */ + 0x00000c2e, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x0000030b, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000008, /* EMC_PDEX2WR */ + 0x00000008, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000008, /* EMC_AR2PDEN */ + 0x00000011, /* EMC_RW2PDEN */ + 0x00000046, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x0000000a, /* EMC_TCKE */ + 0x0000000d, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x00000c6f, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000006, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00007088, /* EMC_FBIO_CFG5 */ + 0x001c0084, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00034000, /* EMC_DLL_XFORM_DQS0 */ + 0x00034000, /* EMC_DLL_XFORM_DQS1 */ + 0x00034000, /* EMC_DLL_XFORM_DQS2 */ + 0x00034000, /* EMC_DLL_XFORM_DQS3 */ + 0x00034000, /* EMC_DLL_XFORM_DQS4 */ + 0x00034000, /* EMC_DLL_XFORM_DQS5 */ + 0x00034000, /* EMC_DLL_XFORM_DQS6 */ + 0x00034000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00040000, /* EMC_DLL_XFORM_DQ0 */ + 0x00040000, /* EMC_DLL_XFORM_DQ1 */ + 0x00040000, /* EMC_DLL_XFORM_DQ2 */ + 0x00040000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800013d, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f508, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x08000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x017f000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x80001941, /* EMC_DYN_SELF_REF_CONTROL */ + 0x0000000c, /* MC_EMEM_ARB_CFG */ + 0xc000004a, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RP */ + 0x0000000a, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000006, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000006, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000009, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06030202, /* MC_EMEM_ARB_DA_TURNS */ + 0x000e070a, /* MC_EMEM_ARB_DA_COVERS */ + 0x7547130b, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0x58000000, /* EMC_FBIO_SPARE */ + 0xff00ff88, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80000731, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 450000, /* SDRAM frequency */ + { + 0x00000014, /* EMC_RC */ + 0x00000046, /* EMC_RFC */ + 0x0000000e, /* EMC_RAS */ + 0x00000005, /* EMC_RP */ + 0x00000003, /* EMC_R2W */ + 0x00000009, /* EMC_W2R */ + 0x00000002, /* EMC_R2P */ + 0x0000000c, /* EMC_W2P */ + 0x00000005, /* EMC_RD_RCD */ + 0x00000005, /* EMC_WR_RCD */ + 0x00000002, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000007, /* EMC_QUSE */ + 0x00000005, /* EMC_QRST */ + 0x0000000a, /* EMC_QSAFE */ + 0x0000000e, /* EMC_RDV */ + 0x00000d76, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x0000035d, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000001, /* EMC_PDEX2WR */ + 0x00000009, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000009, /* EMC_AR2PDEN */ + 0x00000011, /* EMC_RW2PDEN */ + 0x0000004d, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x0000000e, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x00000db6, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000006, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00007088, /* EMC_FBIO_CFG5 */ + 0x00180084, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00022000, /* EMC_DLL_XFORM_DQS0 */ + 0x00022000, /* EMC_DLL_XFORM_DQS1 */ + 0x00022000, /* EMC_DLL_XFORM_DQS2 */ + 0x00022000, /* EMC_DLL_XFORM_DQS3 */ + 0x00022000, /* EMC_DLL_XFORM_DQS4 */ + 0x00022000, /* EMC_DLL_XFORM_DQS5 */ + 0x00022000, /* EMC_DLL_XFORM_DQS6 */ + 0x00022000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00030000, /* EMC_DLL_XFORM_DQ0 */ + 0x00030000, /* EMC_DLL_XFORM_DQ1 */ + 0x00030000, /* EMC_DLL_XFORM_DQ2 */ + 0x00030000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0800013d, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f508, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x08000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x0178000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x80001bc0, /* EMC_DYN_SELF_REF_CONTROL */ + 0x0000000d, /* MC_EMEM_ARB_CFG */ + 0xc0000051, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RP */ + 0x0000000b, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000006, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000006, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000009, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06030202, /* MC_EMEM_ARB_DA_TURNS */ + 0x000f080b, /* MC_EMEM_ARB_DA_COVERS */ + 0x70a7150c, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff8b, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80000731, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 533000, /* SDRAM frequency */ + { + 0x00000018, /* EMC_RC */ + 0x00000054, /* EMC_RFC */ + 0x00000011, /* EMC_RAS */ + 0x00000006, /* EMC_RP */ + 0x00000003, /* EMC_R2W */ + 0x00000009, /* EMC_W2R */ + 0x00000002, /* EMC_R2P */ + 0x0000000d, /* EMC_W2P */ + 0x00000006, /* EMC_RD_RCD */ + 0x00000006, /* EMC_WR_RCD */ + 0x00000002, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000005, /* EMC_WDV */ + 0x00000008, /* EMC_QUSE */ + 0x00000006, /* EMC_QRST */ + 0x00000008, /* EMC_QSAFE */ + 0x00000010, /* EMC_RDV */ + 0x00000ffd, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x000003ff, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x0000000b, /* EMC_PDEX2WR */ + 0x0000000b, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x0000000a, /* EMC_AR2PDEN */ + 0x00000012, /* EMC_RW2PDEN */ + 0x0000005b, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x0000000d, /* EMC_TCKE */ + 0x00000010, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000005, /* EMC_TCLKSTABLE */ + 0x00000006, /* EMC_TCLKSTOP */ + 0x0000103e, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000006, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00007088, /* EMC_FBIO_CFG5 */ + 0x00120084, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00010000, /* EMC_DLL_XFORM_DQS0 */ + 0x00010000, /* EMC_DLL_XFORM_DQS1 */ + 0x00010000, /* EMC_DLL_XFORM_DQS2 */ + 0x00010000, /* EMC_DLL_XFORM_DQS3 */ + 0x00010000, /* EMC_DLL_XFORM_DQS4 */ + 0x00010000, /* EMC_DLL_XFORM_DQS5 */ + 0x00010000, /* EMC_DLL_XFORM_DQS6 */ + 0x00010000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00020000, /* EMC_DLL_XFORM_DQ0 */ + 0x00020000, /* EMC_DLL_XFORM_DQ1 */ + 0x00020000, /* EMC_DLL_XFORM_DQ2 */ + 0x00020000, /* EMC_DLL_XFORM_DQ3 */ + 0x000006a0, /* EMC_XM2CMDPADCTRL */ + 0x0800013d, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77ffc084, /* EMC_XM2CLKPADCTRL */ + 0x01f1f508, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x08000168, /* EMC_XM2QUSEPADCTRL */ + 0x08000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00000000, /* EMC_ZCAL_INTERVAL */ + 0x00000040, /* EMC_ZCAL_WAIT_CNT */ + 0x01ab000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10404, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x800020ae, /* EMC_DYN_SELF_REF_CONTROL */ + 0x0000000f, /* MC_EMEM_ARB_CFG */ + 0xc0000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RP */ + 0x0000000d, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000008, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000007, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000009, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06030202, /* MC_EMEM_ARB_DA_TURNS */ + 0x0010090d, /* MC_EMEM_ARB_DA_COVERS */ + 0x7028180e, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0x00000000, /* EMC_FBIO_SPARE */ + 0xff00ff00, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80000941, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200008, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 667000, /* SDRAM frequency */ + { + 0x0000001f, /* EMC_RC */ + 0x00000069, /* EMC_RFC */ + 0x00000016, /* EMC_RAS */ + 0x00000008, /* EMC_RP */ + 0x00000004, /* EMC_R2W */ + 0x0000000c, /* EMC_W2R */ + 0x00000003, /* EMC_R2P */ + 0x00000011, /* EMC_W2P */ + 0x00000008, /* EMC_RD_RCD */ + 0x00000008, /* EMC_WR_RCD */ + 0x00000002, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000007, /* EMC_WDV */ + 0x0000000b, /* EMC_QUSE */ + 0x00000009, /* EMC_QRST */ + 0x0000000c, /* EMC_QSAFE */ + 0x00000011, /* EMC_RDV */ + 0x00001412, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x00000504, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x0000000e, /* EMC_PDEX2WR */ + 0x0000000e, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x0000000c, /* EMC_AR2PDEN */ + 0x00000016, /* EMC_RW2PDEN */ + 0x00000072, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000010, /* EMC_TCKE */ + 0x00000015, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000006, /* EMC_TCLKSTABLE */ + 0x00000007, /* EMC_TCLKSTOP */ + 0x00001453, /* EMC_TREFBW */ + 0x0000000c, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00005088, /* EMC_FBIO_CFG5 */ + 0x40070191, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00000008, /* EMC_DLL_XFORM_DQS0 */ + 0x00000008, /* EMC_DLL_XFORM_DQS1 */ + 0x00000008, /* EMC_DLL_XFORM_DQS2 */ + 0x00000008, /* EMC_DLL_XFORM_DQS3 */ + 0x00000008, /* EMC_DLL_XFORM_DQS4 */ + 0x00000008, /* EMC_DLL_XFORM_DQS5 */ + 0x00000008, /* EMC_DLL_XFORM_DQS6 */ + 0x00000008, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00000008, /* EMC_DLL_XFORM_DQ0 */ + 0x00000008, /* EMC_DLL_XFORM_DQ1 */ + 0x00000008, /* EMC_DLL_XFORM_DQ2 */ + 0x00000008, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0600013d, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f508, /* EMC_XM2COMPPADCTRL */ + 0x07077404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x07000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x01d6000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x800028a5, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000014, /* MC_EMEM_ARB_CFG */ + 0xc0000079, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000004, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000010, /* MC_EMEM_ARB_TIMING_RC */ + 0x0000000a, /* MC_EMEM_ARB_TIMING_RAS */ + 0x0000000a, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x0000000b, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */ + 0x08040202, /* MC_EMEM_ARB_DA_TURNS */ + 0x00140c10, /* MC_EMEM_ARB_DA_COVERS */ + 0x734a1f11, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xf8000000, /* EMC_FBIO_SPARE */ + 0xff00ff01, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80000b71, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200018, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 750000, /* SDRAM frequency */ + { + 0x00000025, /* EMC_RC */ + 0x0000007e, /* EMC_RFC */ + 0x0000001a, /* EMC_RAS */ + 0x00000009, /* EMC_RP */ + 0x00000004, /* EMC_R2W */ + 0x0000000d, /* EMC_W2R */ + 0x00000004, /* EMC_R2P */ + 0x00000013, /* EMC_W2P */ + 0x00000009, /* EMC_RD_RCD */ + 0x00000009, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000007, /* EMC_WDV */ + 0x0000000b, /* EMC_QUSE */ + 0x00000009, /* EMC_QRST */ + 0x0000000c, /* EMC_QSAFE */ + 0x00000011, /* EMC_RDV */ + 0x0000169a, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x00000608, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000012, /* EMC_PDEX2WR */ + 0x00000012, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x0000000f, /* EMC_AR2PDEN */ + 0x00000018, /* EMC_RW2PDEN */ + 0x00000088, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000014, /* EMC_TCKE */ + 0x00000018, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000007, /* EMC_TCLKSTABLE */ + 0x00000008, /* EMC_TCLKSTOP */ + 0x00001860, /* EMC_TREFBW */ + 0x0000000c, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00005088, /* EMC_FBIO_CFG5 */ + 0xf0080191, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00000008, /* EMC_DLL_XFORM_DQS0 */ + 0x00000008, /* EMC_DLL_XFORM_DQS1 */ + 0x00000008, /* EMC_DLL_XFORM_DQS2 */ + 0x00000008, /* EMC_DLL_XFORM_DQS3 */ + 0x00000008, /* EMC_DLL_XFORM_DQS4 */ + 0x00000008, /* EMC_DLL_XFORM_DQS5 */ + 0x00000008, /* EMC_DLL_XFORM_DQS6 */ + 0x00000008, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ0 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ1 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ2 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0600013d, /* EMC_XM2DQSPADCTRL2 */ + 0x22220000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f501, /* EMC_XM2COMPPADCTRL */ + 0x07077404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x07000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x0180000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000016, /* MC_EMEM_ARB_CFG */ + 0xc0000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000013, /* MC_EMEM_ARB_TIMING_RC */ + 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */ + 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */ + 0x08040202, /* MC_EMEM_ARB_DA_TURNS */ + 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */ + 0x72ac2414, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xf8000000, /* EMC_FBIO_SPARE */ + 0xff00ff49, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80000d71, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200018, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 800000, /* SDRAM frequency */ + { + 0x00000025, /* EMC_RC */ + 0x0000007e, /* EMC_RFC */ + 0x0000001a, /* EMC_RAS */ + 0x00000009, /* EMC_RP */ + 0x00000004, /* EMC_R2W */ + 0x0000000d, /* EMC_W2R */ + 0x00000004, /* EMC_R2P */ + 0x00000013, /* EMC_W2P */ + 0x00000009, /* EMC_RD_RCD */ + 0x00000009, /* EMC_WR_RCD */ + 0x00000003, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000007, /* EMC_WDV */ + 0x0000000b, /* EMC_QUSE */ + 0x00000009, /* EMC_QRST */ + 0x0000000c, /* EMC_QSAFE */ + 0x00000011, /* EMC_RDV */ + 0x00001820, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x00000608, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000012, /* EMC_PDEX2WR */ + 0x00000012, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x0000000f, /* EMC_AR2PDEN */ + 0x00000018, /* EMC_RW2PDEN */ + 0x00000088, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000014, /* EMC_TCKE */ + 0x00000018, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000007, /* EMC_TCLKSTABLE */ + 0x00000008, /* EMC_TCLKSTOP */ + 0x00001860, /* EMC_TREFBW */ + 0x0000000c, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00005088, /* EMC_FBIO_CFG5 */ + 0xf0070191, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x0000800a, /* EMC_DLL_XFORM_DQS0 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS1 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS2 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS3 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS4 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS5 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS6 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x007fc00a, /* EMC_DLL_XFORM_DQ0 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ1 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ2 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0600013d, /* EMC_XM2DQSPADCTRL2 */ + 0x22220000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f501, /* EMC_XM2COMPPADCTRL */ + 0x07077404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x07000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x0180000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000018, /* MC_EMEM_ARB_CFG */ + 0xc0000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000013, /* MC_EMEM_ARB_TIMING_RC */ + 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */ + 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */ + 0x08040202, /* MC_EMEM_ARB_DA_TURNS */ + 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */ + 0x72ac2414, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xf8000000, /* EMC_FBIO_SPARE */ + 0xff00ff49, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80000d71, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200018, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 900000, /* SDRAM frequency */ + { + 0x0000002a, /* EMC_RC */ + 0x0000008e, /* EMC_RFC */ + 0x0000001e, /* EMC_RAS */ + 0x0000000b, /* EMC_RP */ + 0x00000006, /* EMC_R2W */ + 0x0000000f, /* EMC_W2R */ + 0x00000005, /* EMC_R2P */ + 0x00000016, /* EMC_W2P */ + 0x0000000b, /* EMC_RD_RCD */ + 0x0000000b, /* EMC_WR_RCD */ + 0x00000004, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000008, /* EMC_WDV */ + 0x0000000d, /* EMC_QUSE */ + 0x0000000b, /* EMC_QRST */ + 0x0000000b, /* EMC_QSAFE */ + 0x00000014, /* EMC_RDV */ + 0x00001b2c, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x000006cb, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000004, /* EMC_PDEX2WR */ + 0x00000014, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000011, /* EMC_AR2PDEN */ + 0x0000001b, /* EMC_RW2PDEN */ + 0x00000099, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000006, /* EMC_TCKE */ + 0x0000001b, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000008, /* EMC_TCLKSTABLE */ + 0x00000009, /* EMC_TCLKSTOP */ + 0x00001b6c, /* EMC_TREFBW */ + 0x0000000e, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00005088, /* EMC_FBIO_CFG5 */ + 0xf0040191, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x0000800a, /* EMC_DLL_XFORM_DQS0 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS1 */ + 0x007fc00a, /* EMC_DLL_XFORM_DQS2 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS3 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS4 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS5 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS6 */ + 0x0000000a, /* EMC_DLL_XFORM_DQS7 */ + 0x0001c000, /* EMC_DLL_XFORM_QUSE0 */ + 0x0001c000, /* EMC_DLL_XFORM_QUSE1 */ + 0x0001c000, /* EMC_DLL_XFORM_QUSE2 */ + 0x0001c000, /* EMC_DLL_XFORM_QUSE3 */ + 0x0001c000, /* EMC_DLL_XFORM_QUSE4 */ + 0x0001c000, /* EMC_DLL_XFORM_QUSE5 */ + 0x0001c000, /* EMC_DLL_XFORM_QUSE6 */ + 0x0001c000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x007fc00a, /* EMC_DLL_XFORM_DQ0 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ1 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ2 */ + 0x0000000a, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0600013d, /* EMC_XM2DQSPADCTRL2 */ + 0x22220000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f501, /* EMC_XM2COMPPADCTRL */ + 0x07077404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x07000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000120, /* EMC_ZCAL_WAIT_CNT */ + 0x0128000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x8000367d, /* EMC_DYN_SELF_REF_CONTROL */ + 0x0000001b, /* MC_EMEM_ARB_CFG */ + 0xc00000a2, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000006, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000016, /* MC_EMEM_ARB_TIMING_RC */ + 0x0000000e, /* MC_EMEM_ARB_TIMING_RAS */ + 0x0000000d, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000004, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x0000000e, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000005, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000009, /* MC_EMEM_ARB_TIMING_W2R */ + 0x09050202, /* MC_EMEM_ARB_DA_TURNS */ + 0x001a1016, /* MC_EMEM_ARB_DA_COVERS */ + 0x714e2917, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff4b, /* EMC_CFG_RSV */ + }, + 0x00000048, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80000f15, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200020, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, +}; +#endif + +static const struct tegra_emc_table apalis_t30_emc_tables_mt41k256m16re_15e[] = { +//25.5, 51, 102 + { + 0x32, /* Rev 3.2 */ +//204 MHz crashes + 200000, /* SDRAM frequency [kHz] */ + { + 0x0000000a, /* EmcRc */ + 0x00000033, /* EmcRfc */ + 0x00000007, /* EmcRas */ + 0x00000002, /* EmcRp */ + 0x00000003, /* EmcR2w */ + 0x00000009, /* EmcW2r */ + 0x00000005, /* EmcR2p */ + 0x0000000a, /* EmcW2p */ + 0x00000002, /* EmcRdRcd */ + 0x00000002, /* EmcWrRcd */ + 0x00000003, /* EmcRrd */ + 0x00000001, /* EmcRext */ + 0x00000000, /* EmcWext */ + 0x00000004, /* EmcWdv */ + 0x00000005, /* EmcQUse */ + 0x00000004, /* EmcQRst */ + 0x00000009, /* EmcQSafe */ + 0x0000000b, /* EmcRdv */ + 0x000005e9, /* EmcRefresh */ + 0x00000000, /* EmcBurstRefreshNum */ + 0x0000017a, /* EmcPreRefreshReqCnt */ + 0x00000002, /* EmcPdEx2Wr */ + 0x00000002, /* EmcPdEx2Rd */ + 0x00000001, /* EmcPChg2Pden */ + 0x00000000, /* EmcAct2Pden */ + 0x00000007, /* EmcAr2Pden */ + 0x0000000e, /* EmcRw2Pden */ + 0x00000036, /* EmcTxsr */ + 0x00000134, /* EmcTxsrDll */ + 0x00000004, /* EmcTcke */ + 0x0000000a, /* EmcTfaw */ + 0x00000000, /* EmcTrpab */ + 0x00000004, /* EmcTClkStable */ + 0x00000005, /* EmcTClkStop */ + 0x00000618, /* EmcTRefBw */ + 0x00000006, /* EmcQUseExtra */ + 0x00000004, /* EmcFbioCfg6 */ + 0x00000000, /* EmcOdtWrite */ + 0x00000000, /* EmcOdtRead */ + 0x00004288, /* EmcFbioCfg5 */ + 0x004600a4, /* EmcCfgDigDll */ + 0x00008000, /* EmcCfgDigDllPeriod */ + 0x00080000, /* EmcDllXformDqs0 */ + 0x00080000, /* EmcDllXformDqs1 */ + 0x00080000, /* EmcDllXformDqs2 */ + 0x00080000, /* EmcDllXformDqs3 */ + 0x00080000, /* EmcDllXformDqs4 */ + 0x00080000, /* EmcDllXformDqs5 */ + 0x00080000, /* EmcDllXformDqs6 */ + 0x00080000, /* EmcDllXformDqs7 */ + 0x00000000, /* EmcDllXformQUse0 */ + 0x00000000, /* EmcDllXformQUse1 */ + 0x00000000, /* EmcDllXformQUse2 */ + 0x00000000, /* EmcDllXformQUse3 */ + 0x00000000, /* EmcDllXformQUse4 */ + 0x00000000, /* EmcDllXformQUse5 */ + 0x00000000, /* EmcDllXformQUse6 */ + 0x00000000, /* EmcDllXformQUse7 */ + 0x00000000, /* EmcDliTrimTxDqs0 */ + 0x00000000, /* EmcDliTrimTxDqs1 */ + 0x00000000, /* EmcDliTrimTxDqs2 */ + 0x00000000, /* EmcDliTrimTxDqs3 */ + 0x00000000, /* EmcDliTrimTxDqs4 */ + 0x00000000, /* EmcDliTrimTxDqs5 */ + 0x00000000, /* EmcDliTrimTxDqs6 */ + 0x00000000, /* EmcDliTrimTxDqs7 */ + 0x00080000, /* EmcDllXformDq0 */ + 0x00080000, /* EmcDllXformDq1 */ + 0x00080000, /* EmcDllXformDq2 */ + 0x00080000, /* EmcDllXformDq3 */ + 0x000002a0, /* EmcXm2CmdPadCtrl */ + 0x0800211c, /* EmcXm2DqsPadCtrl2 */ + 0x00000000, /* EmcXm2DqPadCtrl2 */ + 0x77fff884, /* EmcXm2ClkPadCtrl */ + 0x01f1f108, /* EmcXm2CompPadCtrl */ + 0x05057404, /* EmcXm2VttGenPadCtrl */ + 0x54000007, /* EmcXm2VttGenPadCtrl2 */ + 0x08000168, /* EmcXm2QUsePadCtrl */ + 0x08000000, /* EmcXm2DqsPadCtrl3 */ + 0x00000802, /* EmcCttTermCtrl */ + 0x00020000, /* EmcZcalInterval */ + 0x00000040, /* EmcZcalWaitCnt */ + 0x000c000c, /* EmcMrsWaitCnt */ + 0x001fffff, /* EmcAutoCalInterval */ + 0x00000000, /* EmcCtt */ + 0x00000000, /* EmcCttDuration */ + 0x80000ce6, /* EmcDynSelfRefControl */ + 0x00000003, /* McEmemArbCfg */ + 0xc0000024, /* McEmemArbOutstandingReq */ + 0x00000001, /* McEmemArbTimingRcd */ + 0x00000001, /* McEmemArbTimingRp */ + 0x00000005, /* McEmemArbTimingRc */ + 0x00000002, /* McEmemArbTimingRas */ + 0x00000004, /* McEmemArbTimingFaw */ + 0x00000001, /* McEmemArbTimingRrd */ + 0x00000003, /* McEmemArbTimingRap2Pre */ + 0x00000007, /* McEmemArbTimingWap2Pre */ + 0x00000002, /* McEmemArbTimingR2R */ + 0x00000001, /* McEmemArbTimingW2W */ + 0x00000003, /* McEmemArbTimingR2W */ + 0x00000006, /* McEmemArbTimingW2R */ + 0x06030102, /* McEmemArbDaTurns */ + 0x00090505, /* McEmemArbDaCovers */ + 0x76a30906, /* McEmemArbMisc0 */ + 0x001f0000, /* McEmemArbRing1Throttle */ + 0xe8000000, /* EmcFbioSpare */ + 0xff00ff00, /* EmcCfgRsv */ + }, + 0x00000040, /* EmcZcalWaitCnt */ + 0x00020000, /* EmcZcalInterval */ + 0x00000001, /* EmcCfg bit 27PERIODIC_QRST */ + 0x80001221, /* EmcMrs */ + 0x80100003, /* EmcEmrs */ + 0x00000000, /* EmcMrw1 */ + 0x00000001, /* EmcCfg bit 28 DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 300000, /* SDRAM frequency [kHz] */ + { + 0x00000010, /* EmcRc */ + 0x0000004d, /* EmcRfc */ + 0x0000000b, /* EmcRas */ + 0x00000003, /* EmcRp */ + 0x00000002, /* EmcR2w */ + 0x00000008, /* EmcW2r */ + 0x00000003, /* EmcR2p */ + 0x00000009, /* EmcW2p */ + 0x00000003, /* EmcRdRcd */ + 0x00000002, /* EmcWrRcd */ + 0x00000002, /* EmcRrd */ + 0x00000001, /* EmcRext */ + 0x00000000, /* EmcWext */ + 0x00000004, /* EmcWdv */ + 0x00000006, /* EmcQUse */ + 0x00000004, /* EmcQRst */ + 0x0000000a, /* EmcQSafe */ + 0x0000000c, /* EmcRdv */ + 0x000008e6, /* EmcRefresh */ + 0x00000000, /* EmcBurstRefreshNum */ + 0x00000240, /* EmcPreRefreshReqCnt */ + 0x0000000a, /* EmcPdEx2Wr */ + 0x00000008, /* EmcPdEx2Rd */ + 0x00000007, /* EmcPChg2Pden */ + 0x00000000, /* EmcAct2Pden */ + 0x00000007, /* EmcAr2Pden */ + 0x0000000e, /* EmcRw2Pden */ + 0x000000b4, /* EmcTxsr */ + 0x00000200, /* EmcTxsrDll */ + 0x00000004, /* EmcTcke */ + 0x00000010, /* EmcTfaw */ + 0x00000000, /* EmcTrpab */ + 0x00000004, /* EmcTClkStable */ + 0x00000005, /* EmcTClkStop */ + 0x00000927, /* EmcTRefBw */ + 0x00000007, /* EmcQUseExtra */ + 0x00000004, /* EmcFbioCfg6 */ + 0x00000000, /* EmcOdtWrite */ + 0x00000000, /* EmcOdtRead */ + 0x00005288, /* EmcFbioCfg5 */ + 0x002b00a4, /* EmcCfgDigDll */ + 0x00008000, /* EmcCfgDigDllPeriod */ + 0x00014000, /* EmcDllXformDqs0 */ + 0x00014000, /* EmcDllXformDqs1 */ + 0x00014000, /* EmcDllXformDqs2 */ + 0x00014000, /* EmcDllXformDqs3 */ + 0x00014000, /* EmcDllXformDqs4 */ + 0x00014000, /* EmcDllXformDqs5 */ + 0x00014000, /* EmcDllXformDqs6 */ + 0x00014000, /* EmcDllXformDqs7 */ + 0x00000000, /* EmcDllXformQUse0 */ + 0x00000000, /* EmcDllXformQUse1 */ + 0x00000000, /* EmcDllXformQUse2 */ + 0x00000000, /* EmcDllXformQUse3 */ + 0x00000000, /* EmcDllXformQUse4 */ + 0x00000000, /* EmcDllXformQUse5 */ + 0x00000000, /* EmcDllXformQUse6 */ + 0x00000000, /* EmcDllXformQUse7 */ + 0x00000000, /* EmcDliTrimTxDqs0 */ + 0x00000000, /* EmcDliTrimTxDqs1 */ + 0x00000000, /* EmcDliTrimTxDqs2 */ + 0x00000000, /* EmcDliTrimTxDqs3 */ + 0x00000000, /* EmcDliTrimTxDqs4 */ + 0x00000000, /* EmcDliTrimTxDqs5 */ + 0x00000000, /* EmcDliTrimTxDqs6 */ + 0x00000000, /* EmcDliTrimTxDqs7 */ + 0x00020000, /* EmcDllXformDq0 */ + 0x00020000, /* EmcDllXformDq1 */ + 0x00020000, /* EmcDllXformDq2 */ + 0x00020000, /* EmcDllXformDq3 */ + 0x000002a0, /* EmcXm2CmdPadCtrl */ + 0x0800211c, /* EmcXm2DqsPadCtrl2 */ + 0x00000000, /* EmcXm2DqPadCtrl2 */ + 0x77fff884, /* EmcXm2ClkPadCtrl */ + 0x01f1f508, /* EmcXm2CompPadCtrl */ + 0x05057404, /* EmcXm2VttGenPadCtrl */ + 0x54000007, /* EmcXm2VttGenPadCtrl2 */ + 0x08000168, /* EmcXm2QUsePadCtrl */ + 0x08000000, /* EmcXm2DqsPadCtrl3 */ + 0x00000802, /* EmcCttTermCtrl */ + 0x00020000, /* EmcZcalInterval */ + 0x00000040, /* EmcZcalWaitCnt */ + 0x0172000c, /* EmcMrsWaitCnt */ + 0x001fffff, /* EmcAutoCalInterval */ + 0x00000000, /* EmcCtt */ + 0x00000000, /* EmcCttDuration */ + 0x800012db, /* EmcDynSelfRefControl */ + 0x00000004, /* McEmemArbCfg */ + 0x80000037, /* McEmemArbOutstandingReq */ + 0x00000001, /* McEmemArbTimingRcd */ + 0x00000001, /* McEmemArbTimingRp */ + 0x00000007, /* McEmemArbTimingRc */ + 0x00000004, /* McEmemArbTimingRas */ + 0x00000007, /* McEmemArbTimingFaw */ + 0x00000001, /* McEmemArbTimingRrd */ + 0x00000002, /* McEmemArbTimingRap2Pre */ + 0x00000007, /* McEmemArbTimingWap2Pre */ + 0x00000002, /* McEmemArbTimingR2R */ + 0x00000002, /* McEmemArbTimingW2W */ + 0x00000005, /* McEmemArbTimingR2W */ + 0x00000006, /* McEmemArbTimingW2R */ + 0x06030202, /* McEmemArbDaTurns */ + 0x000a0507, /* McEmemArbDaCovers */ + 0x70850e08, /* McEmemArbMisc0 */ + 0x001f0000, /* McEmemArbRing1Throttle */ + 0xe8000000, /* EmcFbioSpare */ + 0xff00ff88, /* EmcCfgRsv */ + }, + 0x00000040, /* EmcZcalWaitCnt */ + 0x00020000, /* EmcZcalInterval */ + 0x00000001, /* EmcCfg bit 27PERIODIC_QRST */ + 0x80000321, /* EmcMrs */ + 0x80100002, /* EmcEmrs */ + 0x00000000, /* EmcMrw1 */ + 0x00000000, /* EmcCfg bit 28 DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 333000, /* SDRAM frequency [kHz] */ + { + 0x00000010, /* EmcRc */ + 0x00000055, /* EmcRfc */ + 0x0000000c, /* EmcRas */ + 0x00000004, /* EmcRp */ + 0x00000006, /* EmcR2w */ + 0x00000008, /* EmcW2r */ + 0x00000003, /* EmcR2p */ + 0x00000009, /* EmcW2p */ + 0x00000004, /* EmcRdRcd */ + 0x00000003, /* EmcWrRcd */ + 0x00000002, /* EmcRrd */ + 0x00000001, /* EmcRext */ + 0x00000000, /* EmcWext */ + 0x00000004, /* EmcWdv */ + 0x00000006, /* EmcQUse */ + 0x00000004, /* EmcQRst */ + 0x0000000a, /* EmcQSafe */ + 0x0000000c, /* EmcRdv */ + 0x000009e8, /* EmcRefresh */ + 0x00000000, /* EmcBurstRefreshNum */ + 0x0000027e, /* EmcPreRefreshReqCnt */ + 0x0000000a, /* EmcPdEx2Wr */ + 0x00000008, /* EmcPdEx2Rd */ + 0x00000007, /* EmcPChg2Pden */ + 0x00000000, /* EmcAct2Pden */ + 0x00000007, /* EmcAr2Pden */ + 0x0000000e, /* EmcRw2Pden */ + 0x000000b4, /* EmcTxsr */ + 0x00000200, /* EmcTxsrDll */ + 0x00000004, /* EmcTcke */ + 0x00000015, /* EmcTfaw */ + 0x00000000, /* EmcTrpab */ + 0x00000004, /* EmcTClkStable */ + 0x00000005, /* EmcTClkStop */ + 0x00000a28, /* EmcTRefBw */ + 0x00000000, /* EmcQUseExtra */ + 0x00000006, /* EmcFbioCfg6 */ + 0x00000000, /* EmcOdtWrite */ + 0x00000000, /* EmcOdtRead */ + 0x00007088, /* EmcFbioCfg5 */ + 0x002600a4, /* EmcCfgDigDll */ + 0x00008000, /* EmcCfgDigDllPeriod */ + 0x00014000, /* EmcDllXformDqs0 */ + 0x00014000, /* EmcDllXformDqs1 */ + 0x00014000, /* EmcDllXformDqs2 */ + 0x00014000, /* EmcDllXformDqs3 */ + 0x00014000, /* EmcDllXformDqs4 */ + 0x00014000, /* EmcDllXformDqs5 */ + 0x00014000, /* EmcDllXformDqs6 */ + 0x00014000, /* EmcDllXformDqs7 */ + 0x00000000, /* EmcDllXformQUse0 */ + 0x00000000, /* EmcDllXformQUse1 */ + 0x00000000, /* EmcDllXformQUse2 */ + 0x00000000, /* EmcDllXformQUse3 */ + 0x00000000, /* EmcDllXformQUse4 */ + 0x00000000, /* EmcDllXformQUse5 */ + 0x00000000, /* EmcDllXformQUse6 */ + 0x00000000, /* EmcDllXformQUse7 */ + 0x00000000, /* EmcDliTrimTxDqs0 */ + 0x00000000, /* EmcDliTrimTxDqs1 */ + 0x00000000, /* EmcDliTrimTxDqs2 */ + 0x00000000, /* EmcDliTrimTxDqs3 */ + 0x00000000, /* EmcDliTrimTxDqs4 */ + 0x00000000, /* EmcDliTrimTxDqs5 */ + 0x00000000, /* EmcDliTrimTxDqs6 */ + 0x00000000, /* EmcDliTrimTxDqs7 */ + 0x00020000, /* EmcDllXformDq0 */ + 0x00020000, /* EmcDllXformDq1 */ + 0x00020000, /* EmcDllXformDq2 */ + 0x00020000, /* EmcDllXformDq3 */ + 0x000002a0, /* EmcXm2CmdPadCtrl */ + 0x0800013d, /* EmcXm2DqsPadCtrl2 */ + 0x00000000, /* EmcXm2DqPadCtrl2 */ + 0x77fff884, /* EmcXm2ClkPadCtrl */ + 0x01f1f508, /* EmcXm2CompPadCtrl */ + 0x05057404, /* EmcXm2VttGenPadCtrl */ + 0x54000007, /* EmcXm2VttGenPadCtrl2 */ + 0x080001e8, /* EmcXm2QUsePadCtrl */ + 0x08000021, /* EmcXm2DqsPadCtrl3 */ + 0x00000802, /* EmcCttTermCtrl */ + 0x00020000, /* EmcZcalInterval */ + 0x00000040, /* EmcZcalWaitCnt */ + 0x016a000c, /* EmcMrsWaitCnt */ + 0x001fffff, /* EmcAutoCalInterval */ + 0x00000000, /* EmcCtt */ + 0x00000000, /* EmcCttDuration */ + 0x800014d2, /* EmcDynSelfRefControl */ + 0x00000005, /* McEmemArbCfg */ + 0x8000003c, /* McEmemArbOutstandingReq */ + 0x00000001, /* McEmemArbTimingRcd */ + 0x00000002, /* McEmemArbTimingRp */ + 0x00000008, /* McEmemArbTimingRc */ + 0x00000005, /* McEmemArbTimingRas */ + 0x0000000a, /* McEmemArbTimingFaw */ + 0x00000001, /* McEmemArbTimingRrd */ + 0x00000002, /* McEmemArbTimingRap2Pre */ + 0x00000007, /* McEmemArbTimingWap2Pre */ + 0x00000002, /* McEmemArbTimingR2R */ + 0x00000002, /* McEmemArbTimingW2W */ + 0x00000005, /* McEmemArbTimingR2W */ + 0x00000006, /* McEmemArbTimingW2R */ + 0x06030202, /* McEmemArbDaTurns */ + 0x000b0608, /* McEmemArbDaCovers */ + 0x70850f09, /* McEmemArbMisc0 */ + 0x001f0000, /* McEmemArbRing1Throttle */ + 0xe8000000, /* EmcFbioSpare */ + 0xff00ff88, /* EmcCfgRsv */ + }, + 0x00000040, /* EmcZcalWaitCnt */ + 0x00020000, /* EmcZcalInterval */ + 0x00000000, /* EmcCfg bit 27PERIODIC_QRST */ + 0x80000321, /* EmcMrs */ + 0x80100002, /* EmcEmrs */ + 0x00000000, /* EmcMrw1 */ + 0x00000000, /* EmcCfg bit 28 DYN_SELF_REF */ + }, +//400 + { + 0x32, /* Rev 3.2 */ + 533000, /* SDRAM frequency [kHz] */ + { + 0x0000001a, /* EmcRc */ + 0x0000008b, /* EmcRfc */ + 0x00000013, /* EmcRas */ + 0x00000006, /* EmcRp */ + 0x00000006, /* EmcR2w */ + 0x0000000b, /* EmcW2r */ + 0x00000003, /* EmcR2p */ + 0x0000000e, /* EmcW2p */ + 0x00000006, /* EmcRdRcd */ + 0x00000006, /* EmcWrRcd */ + 0x00000003, /* EmcRrd */ + 0x00000001, /* EmcRext */ + 0x00000000, /* EmcWext */ + 0x00000006, /* EmcWdv */ + 0x00000009, /* EmcQUse */ + 0x00000007, /* EmcQRst */ + 0x0000000a, /* EmcQSafe */ + 0x0000000f, /* EmcRdv */ + 0x0000100b, /* EmcRefresh */ + 0x00000000, /* EmcBurstRefreshNum */ + 0x000003ff, /* EmcPreRefreshReqCnt */ + 0x0000000c, /* EmcPdEx2Wr */ + 0x0000000c, /* EmcPdEx2Rd */ + 0x00000007, /* EmcPChg2Pden */ + 0x00000000, /* EmcAct2Pden */ + 0x0000000a, /* EmcAr2Pden */ + 0x00000012, /* EmcRw2Pden */ + 0x000000b4, /* EmcTxsr */ + 0x00000200, /* EmcTxsrDll */ + 0x00000004, /* EmcTcke */ + 0x0000001e, /* EmcTfaw */ + 0x00000000, /* EmcTrpab */ + 0x00000005, /* EmcTClkStable */ + 0x00000006, /* EmcTClkStop */ + 0x0000103e, /* EmcTRefBw */ + 0x00000000, /* EmcQUseExtra */ + 0x00000006, /* EmcFbioCfg6 */ + 0x00000000, /* EmcOdtWrite */ + 0x00000000, /* EmcOdtRead */ + 0x00007088, /* EmcFbioCfg5 */ + 0xf0120091, /* EmcCfgDigDll */ + 0x00008000, /* EmcCfgDigDllPeriod */ + 0x0000000a, /* EmcDllXformDqs0 */ + 0x0000000a, /* EmcDllXformDqs1 */ + 0x0000000a, /* EmcDllXformDqs2 */ + 0x0000000a, /* EmcDllXformDqs3 */ + 0x0000000a, /* EmcDllXformDqs4 */ + 0x0000000a, /* EmcDllXformDqs5 */ + 0x0000000a, /* EmcDllXformDqs6 */ + 0x0000000a, /* EmcDllXformDqs7 */ + 0x00000000, /* EmcDllXformQUse0 */ + 0x00000000, /* EmcDllXformQUse1 */ + 0x00000000, /* EmcDllXformQUse2 */ + 0x00000000, /* EmcDllXformQUse3 */ + 0x00000000, /* EmcDllXformQUse4 */ + 0x00000000, /* EmcDllXformQUse5 */ + 0x00000000, /* EmcDllXformQUse6 */ + 0x00000000, /* EmcDllXformQUse7 */ + 0x00000000, /* EmcDliTrimTxDqs0 */ + 0x00000000, /* EmcDliTrimTxDqs1 */ + 0x00000000, /* EmcDliTrimTxDqs2 */ + 0x00000000, /* EmcDliTrimTxDqs3 */ + 0x00000000, /* EmcDliTrimTxDqs4 */ + 0x00000000, /* EmcDliTrimTxDqs5 */ + 0x00000000, /* EmcDliTrimTxDqs6 */ + 0x00000000, /* EmcDliTrimTxDqs7 */ + 0x0000000a, /* EmcDllXformDq0 */ + 0x0000000a, /* EmcDllXformDq1 */ + 0x0000000a, /* EmcDllXformDq2 */ + 0x0000000a, /* EmcDllXformDq3 */ + 0x000002a0, /* EmcXm2CmdPadCtrl */ + 0x0800013d, /* EmcXm2DqsPadCtrl2 */ + 0x00000000, /* EmcXm2DqPadCtrl2 */ + 0x77fff884, /* EmcXm2ClkPadCtrl */ + 0x01f1f508, /* EmcXm2CompPadCtrl */ + 0x05057404, /* EmcXm2VttGenPadCtrl */ + 0x54000007, /* EmcXm2VttGenPadCtrl2 */ + 0x080001e8, /* EmcXm2QUsePadCtrl */ + 0x08000021, /* EmcXm2DqsPadCtrl3 */ + 0x00000802, /* EmcCttTermCtrl */ + 0x00020000, /* EmcZcalInterval */ + 0x00000040, /* EmcZcalWaitCnt */ + 0x016b000c, /* EmcMrsWaitCnt */ + 0x001fffff, /* EmcAutoCalInterval */ + 0x00000000, /* EmcCtt */ + 0x00000000, /* EmcCttDuration */ + 0x800020ae, /* EmcDynSelfRefControl */ + 0x00000008, /* McEmemArbCfg */ + 0x80000060, /* McEmemArbOutstandingReq */ + 0x00000002, /* McEmemArbTimingRcd */ + 0x00000003, /* McEmemArbTimingRp */ + 0x0000000d, /* McEmemArbTimingRc */ + 0x00000008, /* McEmemArbTimingRas */ + 0x0000000f, /* McEmemArbTimingFaw */ + 0x00000002, /* McEmemArbTimingRrd */ + 0x00000002, /* McEmemArbTimingRap2Pre */ + 0x00000009, /* McEmemArbTimingWap2Pre */ + 0x00000002, /* McEmemArbTimingR2R */ + 0x00000002, /* McEmemArbTimingW2W */ + 0x00000005, /* McEmemArbTimingR2W */ + 0x00000006, /* McEmemArbTimingW2R */ + 0x06030202, /* McEmemArbDaTurns */ + 0x000f080d, /* McEmemArbDaCovers */ + 0x70c8180e, /* McEmemArbMisc0 */ + 0x001f0000, /* McEmemArbRing1Throttle */ + 0xe8000000, /* EmcFbioSpare */ + 0xff00ff88, /* EmcCfgRsv */ + }, + 0x00000040, /* EmcZcalWaitCnt */ + 0x00020000, /* EmcZcalInterval */ + 0x00000000, /* EmcCfg bit 27PERIODIC_QRST */ + 0x80000931, /* EmcMrs */ + 0x80100002, /* EmcEmrs */ + 0x00000000, /* EmcMrw1 */ + 0x00000000, /* EmcCfg bit 28 DYN_SELF_REF */ + }, +#if 0 + { + 0x32, /* Rev 3.2 */ + 667000, /* SDRAM frequency [kHz] */ + { + 0x0000001f, /* EmcRc */ + 0x000000ac, /* EmcRfc */ + 0x00000016, /* EmcRas */ + 0x00000007, /* EmcRp */ + 0x00000006, /* EmcR2w */ + 0x0000000b, /* EmcW2r */ + 0x00000003, /* EmcR2p */ + 0x00000010, /* EmcW2p */ + 0x00000007, /* EmcRdRcd */ + 0x00000007, /* EmcWrRcd */ + 0x00000003, /* EmcRrd */ + 0x00000001, /* EmcRext */ + 0x00000000, /* EmcWext */ + 0x00000006, /* EmcWdv */ + 0x00000009, /* EmcQUse */ + 0x00000007, /* EmcQRst */ + 0x0000000a, /* EmcQSafe */ + 0x0000000f, /* EmcRdv */ + 0x00001410, /* EmcRefresh */ + 0x00000000, /* EmcBurstRefreshNum */ + 0x00000504, /* EmcPreRefreshReqCnt */ + 0x0000000e, /* EmcPdEx2Wr */ + 0x0000000e, /* EmcPdEx2Rd */ + 0x00000007, /* EmcPChg2Pden */ + 0x00000000, /* EmcAct2Pden */ + 0x0000000c, /* EmcAr2Pden */ + 0x00000015, /* EmcRw2Pden */ + 0x000000b4, /* EmcTxsr */ + 0x00000200, /* EmcTxsrDll */ + 0x00000004, /* EmcTcke */ + 0x0000001e, /* EmcTfaw */ + 0x00000000, /* EmcTrpab */ + 0x00000006, /* EmcTClkStable */ + 0x00000007, /* EmcTClkStop */ + 0x00001450, /* EmcTRefBw */ + 0x0000000a, /* EmcQUseExtra */ + 0x00000006, /* EmcFbioCfg6 */ + 0x00000000, /* EmcOdtWrite */ + 0x00000000, /* EmcOdtRead */ + 0x00005088, /* EmcFbioCfg5 */ + 0xf00b0191, /* EmcCfgDigDll */ + 0x00008000, /* EmcCfgDigDllPeriod */ + 0x0000000a, /* EmcDllXformDqs0 */ + 0x0000000a, /* EmcDllXformDqs1 */ + 0x0000000a, /* EmcDllXformDqs2 */ + 0x0000000a, /* EmcDllXformDqs3 */ + 0x0000000a, /* EmcDllXformDqs4 */ + 0x0000000a, /* EmcDllXformDqs5 */ + 0x0000000a, /* EmcDllXformDqs6 */ + 0x0000000a, /* EmcDllXformDqs7 */ + 0x00000000, /* EmcDllXformQUse0 */ + 0x00000000, /* EmcDllXformQUse1 */ + 0x00000000, /* EmcDllXformQUse2 */ + 0x00000000, /* EmcDllXformQUse3 */ + 0x00000000, /* EmcDllXformQUse4 */ + 0x00000000, /* EmcDllXformQUse5 */ + 0x00000000, /* EmcDllXformQUse6 */ + 0x00000000, /* EmcDllXformQUse7 */ + 0x00000000, /* EmcDliTrimTxDqs0 */ + 0x00000000, /* EmcDliTrimTxDqs1 */ + 0x00000000, /* EmcDliTrimTxDqs2 */ + 0x00000000, /* EmcDliTrimTxDqs3 */ + 0x00000000, /* EmcDliTrimTxDqs4 */ + 0x00000000, /* EmcDliTrimTxDqs5 */ + 0x00000000, /* EmcDliTrimTxDqs6 */ + 0x00000000, /* EmcDliTrimTxDqs7 */ + 0x0000000a, /* EmcDllXformDq0 */ + 0x0000000a, /* EmcDllXformDq1 */ + 0x0000000a, /* EmcDllXformDq2 */ + 0x0000000a, /* EmcDllXformDq3 */ + 0x000002a0, /* EmcXm2CmdPadCtrl */ + 0x0800013d, /* EmcXm2DqsPadCtrl2 */ + 0x22220000, /* EmcXm2DqPadCtrl2 */ + 0x77fff884, /* EmcXm2ClkPadCtrl */ + 0x01f1f508, /* EmcXm2CompPadCtrl */ + 0x07077404, /* EmcXm2VttGenPadCtrl */ + 0x54000000, /* EmcXm2VttGenPadCtrl2 */ + 0x080001e8, /* EmcXm2QUsePadCtrl */ + 0x08000021, /* EmcXm2DqsPadCtrl3 */ + 0x00000802, /* EmcCttTermCtrl */ + 0x00020000, /* EmcZcalInterval */ + 0x00000040, /* EmcZcalWaitCnt */ + 0x0196000c, /* EmcMrsWaitCnt */ + 0x001fffff, /* EmcAutoCalInterval */ + 0x00000000, /* EmcCtt */ + 0x00000000, /* EmcCttDuration */ + 0x800028a0, /* EmcDynSelfRefControl */ + 0x0000000a, /* McEmemArbCfg */ + 0x80000078, /* McEmemArbOutstandingReq */ + 0x00000003, /* McEmemArbTimingRcd */ + 0x00000004, /* McEmemArbTimingRp */ + 0x00000010, /* McEmemArbTimingRc */ + 0x0000000a, /* McEmemArbTimingRas */ + 0x0000000f, /* McEmemArbTimingFaw */ + 0x00000002, /* McEmemArbTimingRrd */ + 0x00000003, /* McEmemArbTimingRap2Pre */ + 0x0000000b, /* McEmemArbTimingWap2Pre */ + 0x00000002, /* McEmemArbTimingR2R */ + 0x00000002, /* McEmemArbTimingW2W */ + 0x00000004, /* McEmemArbTimingR2W */ + 0x00000007, /* McEmemArbTimingW2R */ + 0x07040202, /* McEmemArbDaTurns */ + 0x00130b10, /* McEmemArbDaCovers */ + 0x70ea1e11, /* McEmemArbMisc0 */ + 0x001f0000, /* McEmemArbRing1Throttle */ + 0xe8000000, /* EmcFbioSpare */ + 0xff00ff49, /* EmcCfgRsv */ + }, + 0x00000040, /* EmcZcalWaitCnt */ + 0x00020000, /* EmcZcalInterval */ + 0x00000001, /* EmcCfg bit 27PERIODIC_QRST */ + 0x80000b51, /* EmcMrs */ + 0x80100002, /* EmcEmrs */ + 0x00000000, /* EmcMrw1 */ + 0x00000000, /* EmcCfg bit 28 DYN_SELF_REF */ + }, +//750 +#endif +}; + +int apalis_t30_emc_init(void) +{ +#if 1 + tegra_init_emc(apalis_t30_emc_tables_mt41k256m16re_15e, + ARRAY_SIZE(apalis_t30_emc_tables_mt41k256m16re_15e)); +#else + tegra_init_emc(cardhu_emc_tables_h5tc2g_a2, + ARRAY_SIZE(cardhu_emc_tables_h5tc2g_a2)); +#endif + return 0; +} diff --git a/arch/arm/mach-tegra/board-apalis_t30-panel.c b/arch/arm/mach-tegra/board-apalis_t30-panel.c new file mode 100644 index 000000000000..1be339dce6ef --- /dev/null +++ b/arch/arm/mach-tegra/board-apalis_t30-panel.c @@ -0,0 +1,514 @@ +/* + * arch/arm/mach-tegra/board-apalis_t30-panel.c + * + * Copyright (c) 2013, Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <asm/atomic.h> +#include <asm/mach-types.h> + +#include <linux/delay.h> +#include <linux/earlysuspend.h> +#include <linux/gpio.h> +#include <linux/ion.h> +#include <linux/nvhost.h> +#include <linux/nvmap.h> +#include <linux/platform_device.h> +#include <linux/pwm_backlight.h> +#include <linux/regulator/consumer.h> +#include <linux/resource.h> +#include <linux/tegra_ion.h> + +#include <mach/dc.h> +#include <mach/fb.h> +#include <mach/iomap.h> +#include <mach/irqs.h> +#include <mach/smmu.h> + +#include "board.h" +#include "board-apalis_t30.h" +#include "devices.h" +#include "gpio-names.h" +#include "tegra3_host1x_devices.h" + +#define apalis_t30_bl_enb BKL1_ON +#define apalis_t30_hdmi_hpd HDMI1_HPD + +static struct regulator *apalis_t30_hdmi_pll = NULL; +static struct regulator *apalis_t30_hdmi_reg = NULL; + +static int apalis_t30_backlight_init(struct device *dev) { + int ret; + + ret = gpio_request(apalis_t30_bl_enb, "BKL1_ON"); + if (ret < 0) + return ret; + + ret = gpio_direction_output(apalis_t30_bl_enb, 1); + if (ret < 0) + gpio_free(apalis_t30_bl_enb); + + return ret; +}; + +static void apalis_t30_backlight_exit(struct device *dev) { + gpio_set_value(apalis_t30_bl_enb, 0); + gpio_free(apalis_t30_bl_enb); +} + +static int apalis_t30_backlight_notify(struct device *dev, int brightness) +{ + struct platform_pwm_backlight_data *pdata = dev->platform_data; + + gpio_set_value(apalis_t30_bl_enb, !!brightness); + + /* Unified TFT interface displays (e.g. EDT ET070080DH6) LEDCTRL pin + with inverted behaviour (e.g. 0V brightest vs. 3.3V darkest) + Note: brightness polarity display model specific */ + if (brightness) return pdata->max_brightness - brightness; + else return brightness; +} + +static int apalis_t30_disp1_check_fb(struct device *dev, struct fb_info *info); + +static struct platform_pwm_backlight_data apalis_t30_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 127, + .pwm_period_ns = 1000000, /* 1 kHz */ + .init = apalis_t30_backlight_init, + .exit = apalis_t30_backlight_exit, + .notify = apalis_t30_backlight_notify, + /* Only toggle backlight on fb blank notifications for disp1 */ + .check_fb = apalis_t30_disp1_check_fb, +}; + +static struct platform_device apalis_t30_backlight_device = { + .name = "pwm-backlight", + .id = -1, + .dev = { + .platform_data = &apalis_t30_backlight_data, + }, +}; + +static int apalis_t30_panel_enable(void) +{ + return 0; +} + +static int apalis_t30_panel_disable(void) +{ + return 0; +} + +#ifdef CONFIG_TEGRA_DC + +static int apalis_t30_hdmi_enable(void) +{ + int ret; + if (!apalis_t30_hdmi_reg) { + apalis_t30_hdmi_reg = regulator_get(NULL, "avdd_hdmi"); + if (IS_ERR_OR_NULL(apalis_t30_hdmi_reg)) { + pr_err("hdmi: couldn't get regulator avdd_hdmi\n"); + apalis_t30_hdmi_reg = NULL; + return PTR_ERR(apalis_t30_hdmi_reg); + } + } + ret = regulator_enable(apalis_t30_hdmi_reg); + if (ret < 0) { + pr_err("hdmi: couldn't enable regulator avdd_hdmi\n"); + return ret; + } + if (!apalis_t30_hdmi_pll) { + apalis_t30_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll"); + if (IS_ERR_OR_NULL(apalis_t30_hdmi_pll)) { + pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n"); + apalis_t30_hdmi_pll = NULL; + regulator_put(apalis_t30_hdmi_reg); + apalis_t30_hdmi_reg = NULL; + return PTR_ERR(apalis_t30_hdmi_pll); + } + } + ret = regulator_enable(apalis_t30_hdmi_pll); + if (ret < 0) { + pr_err("hdmi: couldn't enable regulator avdd_hdmi_pll\n"); + return ret; + } + return 0; +} + +static int apalis_t30_hdmi_disable(void) +{ + regulator_disable(apalis_t30_hdmi_reg); + regulator_put(apalis_t30_hdmi_reg); + apalis_t30_hdmi_reg = NULL; + + regulator_disable(apalis_t30_hdmi_pll); + regulator_put(apalis_t30_hdmi_pll); + apalis_t30_hdmi_pll = NULL; + return 0; +} +static struct resource apalis_t30_disp1_resources[] = { + { + .name = "irq", + .start = INT_DISPLAY_GENERAL, + .end = INT_DISPLAY_GENERAL, + .flags = IORESOURCE_IRQ, + }, + { + .name = "regs", + .start = TEGRA_DISPLAY_BASE, + .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1, + .flags = IORESOURCE_MEM, + }, + { + .name = "fbmem", + .start = 0, /* Filled in by apalis_t30_panel_init() */ + .end = 0, /* Filled in by apalis_t30_panel_init() */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource apalis_t30_disp2_resources[] = { + { + .name = "irq", + .start = INT_DISPLAY_B_GENERAL, + .end = INT_DISPLAY_B_GENERAL, + .flags = IORESOURCE_IRQ, + }, + { + .name = "regs", + .start = TEGRA_DISPLAY2_BASE, + .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "fbmem", + .flags = IORESOURCE_MEM, + .start = 0, + .end = 0, + }, + { + .name = "hdmi_regs", + .start = TEGRA_HDMI_BASE, + .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; +#endif /* CONFIG_TEGRA_DC */ + + +#ifdef CONFIG_TEGRA_DC +static struct tegra_fb_data apalis_t30_fb_data = { + .win = 0, + .flags = TEGRA_FB_FLIP_ON_PROBE, +}; + +static struct tegra_fb_data apalis_t30_hdmi_fb_data = { + .win = 0, + .flags = TEGRA_FB_FLIP_ON_PROBE, +}; + +static struct tegra_dc_out_pin apalis_t30_dc_out_pins[] = { + { + .name = TEGRA_DC_OUT_PIN_H_SYNC, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, + { + .name = TEGRA_DC_OUT_PIN_V_SYNC, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, + { + .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, +}; + +static struct tegra_dc_out apalis_t30_disp1_out = { + .type = TEGRA_DC_OUT_RGB, + .parent_clk = "pll_d_out0", + .parent_clk_backup = "pll_d2_out0", + + .align = TEGRA_DC_ALIGN_MSB, + .order = TEGRA_DC_ORDER_RED_BLUE, + .depth = 24, + .dither = TEGRA_DC_ORDERED_DITHER, + + .default_mode = "640x480-16@60", + + .out_pins = apalis_t30_dc_out_pins, + .n_out_pins = ARRAY_SIZE(apalis_t30_dc_out_pins), + + .enable = apalis_t30_panel_enable, + .disable = apalis_t30_panel_disable, +}; + +static struct tegra_dc_out apalis_t30_disp2_out = { + .type = TEGRA_DC_OUT_HDMI, + .flags = TEGRA_DC_OUT_HOTPLUG_HIGH, + .parent_clk = "pll_d2_out0", + + .dcc_bus = 3, + .hotplug_gpio = apalis_t30_hdmi_hpd, + + .max_pixclock = KHZ2PICOS(148500), + + .default_mode = "640x480-16@60", + + .align = TEGRA_DC_ALIGN_MSB, + .order = TEGRA_DC_ORDER_RED_BLUE, + + .enable = apalis_t30_hdmi_enable, + .disable = apalis_t30_hdmi_disable, +}; + +static struct tegra_dc_platform_data apalis_t30_disp1_pdata = { + .flags = TEGRA_DC_FLAG_ENABLED, + .default_out = &apalis_t30_disp1_out, + .emc_clk_rate = 300000000, + .fb = &apalis_t30_fb_data, +}; + +static struct tegra_dc_platform_data apalis_t30_disp2_pdata = { + .flags = TEGRA_DC_FLAG_ENABLED, + .default_out = &apalis_t30_disp2_out, + .fb = &apalis_t30_hdmi_fb_data, + .emc_clk_rate = 300000000, +}; + +static struct nvhost_device apalis_t30_disp1_device = { + .name = "tegradc", + .id = 0, + .resource = apalis_t30_disp1_resources, + .num_resources = ARRAY_SIZE(apalis_t30_disp1_resources), + .dev = { + .platform_data = &apalis_t30_disp1_pdata, + }, +}; + +static int apalis_t30_disp1_check_fb(struct device *dev, struct fb_info *info) +{ + return info->device == &apalis_t30_disp1_device.dev; +} + +static struct nvhost_device apalis_t30_disp2_device = { + .name = "tegradc", + .id = 1, + .resource = apalis_t30_disp2_resources, + .num_resources = ARRAY_SIZE(apalis_t30_disp2_resources), + .dev = { + .platform_data = &apalis_t30_disp2_pdata, + }, +}; +#else /* CONFIG_TEGRA_DC */ +static int apalis_t30_disp1_check_fb(struct device *dev, struct fb_info *info) +{ + return 0; +} +#endif /* CONFIG_TEGRA_DC */ + +#if defined(CONFIG_TEGRA_NVMAP) +static struct nvmap_platform_carveout apalis_t30_carveouts[] = { + [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT, + [1] = { + .name = "generic-0", + .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC, + .base = 0, /* Filled in by apalis_t30_panel_init() */ + .size = 0, /* Filled in by apalis_t30_panel_init() */ + .buddy_size = SZ_32K, + }, +}; + +static struct nvmap_platform_data apalis_t30_nvmap_data = { + .carveouts = apalis_t30_carveouts, + .nr_carveouts = ARRAY_SIZE(apalis_t30_carveouts), +}; + +static struct platform_device apalis_t30_nvmap_device = { + .name = "tegra-nvmap", + .id = -1, + .dev = { + .platform_data = &apalis_t30_nvmap_data, + }, +}; +#endif /* CONFIG_TEGRA_NVMAP */ + +#if defined(CONFIG_ION_TEGRA) +static struct platform_device tegra_iommu_device = { + .name = "tegra_iommu_device", + .id = -1, + .dev = { + .platform_data = (void *)((1 << HWGRP_COUNT) - 1), + }, +}; + +static struct ion_platform_data tegra_ion_data = { + .nr = 4, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = TEGRA_ION_HEAP_CARVEOUT, + .name = "carveout", + .base = 0, + .size = 0, + }, + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = TEGRA_ION_HEAP_IRAM, + .name = "iram", + .base = TEGRA_IRAM_BASE + TEGRA_RESET_HANDLER_SIZE, + .size = TEGRA_IRAM_SIZE - TEGRA_RESET_HANDLER_SIZE, + }, + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = TEGRA_ION_HEAP_VPR, + .name = "vpr", + .base = 0, + .size = 0, + }, + { + .type = ION_HEAP_TYPE_IOMMU, + .id = TEGRA_ION_HEAP_IOMMU, + .name = "iommu", + .base = TEGRA_SMMU_BASE, + .size = TEGRA_SMMU_SIZE, + .priv = &tegra_iommu_device.dev, + }, + }, +}; + +static struct platform_device tegra_ion_device = { + .name = "ion-tegra", + .id = -1, + .dev = { + .platform_data = &tegra_ion_data, + }, +}; +#endif /* CONFIG_ION_TEGRA */ + +static struct platform_device *apalis_t30_gfx_devices[] __initdata = { +#if defined(CONFIG_TEGRA_NVMAP) + &apalis_t30_nvmap_device, +#endif +#if defined(CONFIG_ION_TEGRA) + &tegra_ion_device, +#endif + &tegra_pwfm0_device, + &apalis_t30_backlight_device, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +/* put early_suspend/late_resume handlers here for the display in order + * to keep the code out of the display driver, keeping it closer to upstream + */ +struct early_suspend apalis_t30_panel_early_suspender; + +static void apalis_t30_panel_early_suspend(struct early_suspend *h) +{ + /* power down LCD, add use a black screen for HDMI */ + if (num_registered_fb > 0) + fb_blank(registered_fb[0], FB_BLANK_POWERDOWN); + if (num_registered_fb > 1) + fb_blank(registered_fb[1], FB_BLANK_NORMAL); +} + +static void apalis_t30_panel_late_resume(struct early_suspend *h) +{ + unsigned i; + for (i = 0; i < num_registered_fb; i++) + fb_blank(registered_fb[i], FB_BLANK_UNBLANK); +} +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +int __init apalis_t30_panel_init(void) +{ + int err = 0; + struct resource *res; + void __iomem *to_io; + + /* enable hdmi hotplug gpio for hotplug detection */ + gpio_request(apalis_t30_hdmi_hpd, "HDMI1_HPD"); + gpio_direction_input(apalis_t30_hdmi_hpd); + +#ifdef CONFIG_HAS_EARLYSUSPEND + apalis_t30_panel_early_suspender.suspend = apalis_t30_panel_early_suspend; + apalis_t30_panel_early_suspender.resume = apalis_t30_panel_late_resume; + apalis_t30_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + register_early_suspend(&apalis_t30_panel_early_suspender); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +#ifdef CONFIG_TEGRA_NVMAP + apalis_t30_carveouts[1].base = tegra_carveout_start; + apalis_t30_carveouts[1].size = tegra_carveout_size; +#endif /* CONFIG_TEGRA_NVMAP */ + +#ifdef CONFIG_ION_TEGRA + tegra_ion_data.heaps[0].base = tegra_carveout_start; + tegra_ion_data.heaps[0].size = tegra_carveout_size; +#endif /* CONFIG_ION_TEGRA */ + +#ifdef CONFIG_TEGRA_GRHOST + err = tegra3_register_host1x_devices(); + if (err) + return err; +#endif /* CONFIG_TEGRA_GRHOST */ + + err = platform_add_devices(apalis_t30_gfx_devices, + ARRAY_SIZE(apalis_t30_gfx_devices)); + +#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) + res = nvhost_get_resource_byname(&apalis_t30_disp1_device, + IORESOURCE_MEM, "fbmem"); + res->start = tegra_fb_start; + res->end = tegra_fb_start + tegra_fb_size - 1; + + res = nvhost_get_resource_byname(&apalis_t30_disp2_device, + IORESOURCE_MEM, "fbmem"); + res->start = tegra_fb2_start; + res->end = tegra_fb2_start + tegra_fb2_size - 1; +#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */ + + /* Make sure LVDS framebuffer is cleared. */ + to_io = ioremap(tegra_fb_start, tegra_fb_size); + if (to_io) { + memset(to_io, 0, tegra_fb_size); + iounmap(to_io); + } else pr_err("%s: Failed to map LVDS framebuffer\n", __func__); + + /* Make sure HDMI framebuffer is cleared. + Note: this seems to fix a tegradc.1 initialisation race in case of + framebuffer console as well. */ + to_io = ioremap(tegra_fb2_start, tegra_fb2_size); + if (to_io) { + memset(to_io, 0, tegra_fb2_size); + iounmap(to_io); + } else pr_err("%s: Failed to map HDMI framebuffer\n", __func__); + +#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) + if (!err) + err = nvhost_device_register(&apalis_t30_disp1_device); + + if (!err) + err = nvhost_device_register(&apalis_t30_disp2_device); +#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */ + +#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_NVAVP) + if (!err) + err = nvhost_device_register(&nvavp_device); +#endif + return err; +} diff --git a/arch/arm/mach-tegra/board-apalis_t30-pinmux.c b/arch/arm/mach-tegra/board-apalis_t30-pinmux.c new file mode 100644 index 000000000000..a04a15587129 --- /dev/null +++ b/arch/arm/mach-tegra/board-apalis_t30-pinmux.c @@ -0,0 +1,487 @@ +/* + * arch/arm/mach-tegra/board-apalis_t30-pinmux.c + * + * Copyright (C) 2013 Toradex, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> + +#include <mach/pinmux.h> + +#include "board-apalis_t30.h" +#include "board.h" +#include "gpio-names.h" + +#define DEFAULT_DRIVE(_name) \ + { \ + .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \ + .hsm = TEGRA_HSM_DISABLE, \ + .schmitt = TEGRA_SCHMITT_ENABLE, \ + .drive = TEGRA_DRIVE_DIV_1, \ + .pull_down = TEGRA_PULL_31, \ + .pull_up = TEGRA_PULL_31, \ + .slew_rising = TEGRA_SLEW_SLOWEST, \ + .slew_falling = TEGRA_SLEW_SLOWEST, \ + } + +/* Setting the drive strength of pins + * hsm: Enable High speed mode (ENABLE/DISABLE) + * Schimit: Enable/disable schimit (ENABLE/DISABLE) + * drive: low power mode (DIV_1, DIV_2, DIV_4, DIV_8) + * pulldn_drive - drive down (falling edge) - Driver Output Pull-Down drive + * strength code. Value from 0 to 31. + * pullup_drive - drive up (rising edge) - Driver Output Pull-Up drive + * strength code. Value from 0 to 31. + * pulldn_slew - Driver Output Pull-Up slew control code - 2bit code + * code 11 is least slewing of signal. code 00 is highest + * slewing of the signal. + * Value - FASTEST, FAST, SLOW, SLOWEST + * pullup_slew - Driver Output Pull-Down slew control code - + * code 11 is least slewing of signal. code 00 is highest + * slewing of the signal. + * Value - FASTEST, FAST, SLOW, SLOWEST + */ +#define SET_DRIVE(_name, _hsm, _schmitt, _drive, _pulldn_drive, _pullup_drive, _pulldn_slew, _pullup_slew) \ + { \ + .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \ + .hsm = TEGRA_HSM_##_hsm, \ + .schmitt = TEGRA_SCHMITT_##_schmitt, \ + .drive = TEGRA_DRIVE_##_drive, \ + .pull_down = TEGRA_PULL_##_pulldn_drive, \ + .pull_up = TEGRA_PULL_##_pullup_drive, \ + .slew_rising = TEGRA_SLEW_##_pulldn_slew, \ + .slew_falling = TEGRA_SLEW_##_pullup_slew, \ + } + +static __initdata struct tegra_drive_pingroup_config apalis_t30_drive_pinmux[] = { + /* DEFAULT_DRIVE(<pin_group>), */ + + /* Audio codec */ + SET_DRIVE(DAP2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + + /* All I2C pins are driven to maximum drive strength */ + + /* GEN1_I2C: I2C_SDA/SCL on SODIMM pin 194/196 (e.g. RTC on carrier board) */ + SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + + /* DDC_CLOCK/DATA on X3 pin 15/16 (e.g. display EDID) */ + SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + + /* PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and + touch screen controller */ + SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + + /* SDMMC2 */ + SET_DRIVE(AO2, DISABLE, DISABLE, DIV_1, 46, 42, FAST, FAST), + + /* eMMC on SDMMC4 */ + SET_DRIVE(GMA, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST), + SET_DRIVE(GMB, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST), + SET_DRIVE(GMC, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST), + SET_DRIVE(GMD, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST), +}; + +#define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \ + { \ + .pingroup = TEGRA_PINGROUP_##_pingroup, \ + .func = TEGRA_MUX_##_mux, \ + .pupd = TEGRA_PUPD_##_pupd, \ +/* TRISTATE here means output driver is tri-stated */ \ + .tristate = TEGRA_TRI_##_tri, \ +/* INPUT here means input driver is enabled vs. OUTPUT where it is disabled */ \ + .io = TEGRA_PIN_##_io, \ + .lock = TEGRA_PIN_LOCK_DEFAULT, \ + .od = TEGRA_PIN_OD_DEFAULT, \ + .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \ + } + +#define I2C_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _od) \ + { \ + .pingroup = TEGRA_PINGROUP_##_pingroup, \ + .func = TEGRA_MUX_##_mux, \ + .pupd = TEGRA_PUPD_##_pupd, \ + .tristate = TEGRA_TRI_##_tri, \ + .io = TEGRA_PIN_##_io, \ + .lock = TEGRA_PIN_LOCK_##_lock, \ + .od = TEGRA_PIN_OD_##_od, \ + .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \ + } + +#define VI_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _ioreset) \ + { \ + .pingroup = TEGRA_PINGROUP_##_pingroup, \ + .func = TEGRA_MUX_##_mux, \ + .pupd = TEGRA_PUPD_##_pupd, \ + .tristate = TEGRA_TRI_##_tri, \ + .io = TEGRA_PIN_##_io, \ + .lock = TEGRA_PIN_LOCK_##_lock, \ + .od = TEGRA_PIN_OD_DEFAULT, \ + .ioreset = TEGRA_PIN_IO_RESET_##_ioreset \ + } + +static __initdata struct tegra_pingroup_config apalis_t30_pinmux[] = { + I2C_PINMUX(CAM_I2C_SCL, I2C3, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + I2C_PINMUX(CAM_I2C_SDA, I2C3, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(CLK1_REQ, HDA, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(CLK2_OUT, EXTPERIPH2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(CLK2_REQ, RSVD1, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(CLK3_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(CLK3_REQ, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(CLK_32K_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(CRT_HSYNC, CRT, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(CRT_VSYNC, CRT, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(DAP1_DIN, HDA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP1_DOUT, HDA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP1_FS, HDA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP1_SCLK, HDA, NORMAL, NORMAL, INPUT), + +//multiplexed CAN1/2_RX/TX + DEFAULT_PINMUX(DAP2_DIN, RSVD2, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(DAP2_DOUT, RSVD2, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(DAP2_FS, RSVD2, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(DAP2_SCLK, RSVD2, NORMAL, TRISTATE, OUTPUT), + + DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(DAP4_DIN, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(DAP4_DOUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(DAP4_FS, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(DAP4_SCLK, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + I2C_PINMUX(DDC_SCL, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + I2C_PINMUX(DDC_SDA, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + + I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + I2C_PINMUX(GEN1_I2C_SDA, I2C1, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + + I2C_PINMUX(GEN2_I2C_SCL, RSVD3, NORMAL, NORMAL, INPUT, DEFAULT, DISABLE), + I2C_PINMUX(GEN2_I2C_SDA, RSVD3, NORMAL, NORMAL, INPUT, DEFAULT, DISABLE), + + DEFAULT_PINMUX(GMI_A16, SPI4, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_A17, SPI4, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_A18, SPI4, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_A19, SPI4, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(GMI_AD0, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD1, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD2, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD3, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD4, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD5, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD6, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD7, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD8, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD9, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD10, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD11, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD12, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD13, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD14, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_AD15, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_ADV_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_CLK, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_CS0_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_CS1_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_CS2_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_CS3_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_CS4_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_CS6_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_CS7_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_DQS, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_IORDY, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(GMI_OE_N, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_RST_N, RSVD3, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(GMI_WAIT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_WP_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(GMI_WR_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PBB4, VGP4, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PBB5, VGP5, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PBB6, VGP6, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PBB7, RSVD1, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PCC2, RSVD1, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(GPIO_PU0, GMI, PULL_DOWN, NORMAL, OUTPUT), /* NC */ + DEFAULT_PINMUX(GPIO_PU1, GMI, PULL_DOWN, NORMAL, OUTPUT), /* NC */ + DEFAULT_PINMUX(GPIO_PU2, GMI, PULL_DOWN, NORMAL, OUTPUT), /* NC */ + + DEFAULT_PINMUX(GPIO_PU3, PWM0, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PU4, PWM1, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PU5, PWM2, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GPIO_PU6, PWM3, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(GPIO_PV0, RSVD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PV1, RSVD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(HDMI_CEC, CEC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(HDMI_INT, RSVD0, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(JTAG_RTCK, RTCK, NORMAL, NORMAL, OUTPUT), + +//multiplexed OWR + DEFAULT_PINMUX(KB_COL0, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_COL1, KBC, NORMAL, NORMAL, INPUT), + +//multiplexed VI_PCLK, VI_VSYNC and VI_HSYNC + DEFAULT_PINMUX(KB_COL2, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL3, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL4, KBC, NORMAL, TRISTATE, INPUT), + +//multiplexed VI_D11 + DEFAULT_PINMUX(KB_COL5, KBC, NORMAL, NORMAL, INPUT), +//multiplexed VI_D10 + DEFAULT_PINMUX(KB_COL6, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_COL7, KBC, NORMAL, NORMAL, INPUT), + +//multiplexed VI_D2, VI_D3, VI_D4, VI_D5, VI_D6, VI_D7, VI_D8 and VI_D9 + DEFAULT_PINMUX(KB_ROW0, RSVD2, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW1, RSVD2, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW2, RSVD2, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW3, RSVD2, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW4, RSVD3, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW5, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW6, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW7, KBC, NORMAL, TRISTATE, INPUT), + +//multiplexed VI_D0 + DEFAULT_PINMUX(KB_ROW8, KBC, NORMAL, NORMAL, INPUT), +//multiplexed VI_D1 + DEFAULT_PINMUX(KB_ROW9, KBC, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(KB_ROW10, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW11, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW13, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW14, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW15, KBC, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(LCD_CS0_N, SPI5, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(LCD_CS1_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D5, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D6, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D7, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D9, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D10, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D11, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D12, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D19, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D20, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D22, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(LCD_DC0, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(LCD_DC1, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_HSYNC, DISPLAYA, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(LCD_M1, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(LCD_PCLK, DISPLAYA, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(LCD_PWR0, DISPLAYB, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(LCD_PWR1, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(LCD_PWR2, RSVD, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(LCD_SCK, SPI5, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_SDIN, SPI5, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_SDOUT, SPI5, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(LCD_VSYNC, DISPLAYA, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(LCD_WR_N, RSVD, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + +//multiplexed KB_COL0 + DEFAULT_PINMUX(OWR, OWR, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(PEX_L0_CLKREQ_N, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_L0_PRSNT_N, RSVD2, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(PEX_L0_RST_N, RSVD2, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(PEX_L1_PRSNT_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(PEX_L1_RST_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(PEX_L2_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_L2_PRSNT_N, PCIE, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_L2_RST_N, PCIE, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(PEX_WAKE_N, PCIE, NORMAL, NORMAL, INPUT), + +/* Power I2C pinmux */ + I2C_PINMUX(PWR_I2C_SCL, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + I2C_PINMUX(PWR_I2C_SDA, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + + DEFAULT_PINMUX(SDMMC1_CLK, SDMMC1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_CMD, SDMMC1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_DAT0, SDMMC1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_DAT1, SDMMC1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_DAT2, SDMMC1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_DAT3, SDMMC1, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(SDMMC3_CLK, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT0, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT1, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT2, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT3, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT6, SDMMC3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT7, SDMMC3, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(SDMMC4_CLK, SDMMC4, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT0, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT1, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT2, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT3, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT4, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT5, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT6, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT7, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_RST_N, RSVD1, PULL_DOWN, NORMAL, INPUT), + + DEFAULT_PINMUX(SPDIF_IN, SPDIF, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPDIF_OUT, SPDIF, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(SPI1_CS0_N, SPI1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI1_MISO, SPI1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI1_MOSI, SPI1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI1_SCK, SPI1, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(SPI2_CS0_N, SPI2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI2_CS1_N, SPI2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI2_CS2_N, SPI2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI2_MISO, SPI2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI2_MOSI, SPI2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI2_SCK, SPI2, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(SYS_CLK_REQ, SYSCLK, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(UART2_CTS_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(UART2_RTS_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(UART2_TXD, IRDA, NORMAL, NORMAL, OUTPUT), + +//disable BKL1_PWM_EN# (e.g. PMIC PWM backlight enable) for now + DEFAULT_PINMUX(UART3_CTS_N, RSVD1, PULL_UP, NORMAL, OUTPUT), + DEFAULT_PINMUX(UART3_RTS_N, PWM0, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(UART3_RXD, UARTC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(UART3_TXD, UARTC, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(ULPI_CLK, UARTD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA0, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA1, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA2, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA3, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA4, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA5, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA6, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA7, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DIR, UARTD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_NXT, UARTD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_STP, UARTD, NORMAL, NORMAL, INPUT), + +//VI pins are all input level-shifted and multiplexed +//unused VI pins could disable input drivers + VI_PINMUX(VI_D0, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D1, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D2, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D3, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D4, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D5, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D6, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D7, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D8, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D9, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D10, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D11, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_HSYNC, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + DEFAULT_PINMUX(VI_MCLK, VI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + VI_PINMUX(VI_PCLK, VI, PULL_UP, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_VSYNC, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), +}; + +#define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \ + { \ + .gpio_nr = _gpio, \ + .is_input = _is_input, \ + .value = _value, \ + } + +static struct gpio_init_pin_info apalis_t30_init_gpio_mode[] = { +}; + +static void __init apalis_t30_gpio_init_configure(void) +{ + int len; + int i; + struct gpio_init_pin_info *pins_info; + + len = ARRAY_SIZE(apalis_t30_init_gpio_mode); + pins_info = apalis_t30_init_gpio_mode; + + for (i = 0; i < len; ++i) { + tegra_gpio_init_configure(pins_info->gpio_nr, + pins_info->is_input, + pins_info->value); + pins_info++; + } +} + +int __init apalis_t30_pinmux_init(void) +{ + apalis_t30_gpio_init_configure(); + + tegra_pinmux_config_table(apalis_t30_pinmux, + ARRAY_SIZE(apalis_t30_pinmux)); + tegra_drive_pinmux_config_table(apalis_t30_drive_pinmux, + ARRAY_SIZE(apalis_t30_drive_pinmux)); + + return 0; +} diff --git a/arch/arm/mach-tegra/board-apalis_t30-power.c b/arch/arm/mach-tegra/board-apalis_t30-power.c new file mode 100644 index 000000000000..7b2744a0fe8b --- /dev/null +++ b/arch/arm/mach-tegra/board-apalis_t30-power.c @@ -0,0 +1,509 @@ +/* + * arch/arm/mach-tegra/board-apalis_t30-power.c + * + * Copyright (C) 2013 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <asm/mach-types.h> + +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/mfd/tps6591x.h> +#include <linux/platform_device.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/tps62360.h> +#include <linux/regulator/tps6591x-regulator.h> +#include <linux/resource.h> + +#include <mach/edp.h> +#include <mach/iomap.h> +#include <mach/irqs.h> +#include <mach/pinmux.h> + +#include "board-apalis_t30.h" +#include "board.h" +#include "gpio-names.h" +#include "tegra3_tsensor.h" +#include "pm.h" +#include "wakeups.h" +#include "wakeups-t3.h" + +#define PMC_CTRL 0x0 +#define PMC_CTRL_INTR_LOW (1 << 17) + +/* SW1: +V1.35_VDDIO_DDR */ +static struct regulator_consumer_supply tps6591x_vdd1_supply_0[] = { + REGULATOR_SUPPLY("mem_vddio_ddr", NULL), + REGULATOR_SUPPLY("t30_vddio_ddr", NULL), +}; + +/* SW2: +V1.05 */ +static struct regulator_consumer_supply tps6591x_vdd2_supply_0[] = { + REGULATOR_SUPPLY("avdd_sata", NULL), + REGULATOR_SUPPLY("vdd_sata", NULL), + REGULATOR_SUPPLY("avdd_sata_pll", NULL), +}; + +/* SW CTRL: +V1.0_VDD_CPU */ +static struct regulator_consumer_supply tps6591x_vddctrl_supply_0[] = { + REGULATOR_SUPPLY("vdd_cpu_pmu", NULL), + REGULATOR_SUPPLY("vdd_cpu", NULL), +//!=vddio_sys! + REGULATOR_SUPPLY("vdd_sys", NULL), +}; + +/* SWIO: +V1.8 */ +static struct regulator_consumer_supply tps6591x_vio_supply_0[] = { + REGULATOR_SUPPLY("vdd_gen1v8", NULL), + REGULATOR_SUPPLY("avdd_usb_pll", NULL), + REGULATOR_SUPPLY("avdd_osc", NULL), + REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.3"), + REGULATOR_SUPPLY("pwrdet_sdmmc4", NULL), + REGULATOR_SUPPLY("vdd1v8_satelite", NULL), + REGULATOR_SUPPLY("vddio_vi", NULL), + REGULATOR_SUPPLY("pwrdet_vi", NULL), + REGULATOR_SUPPLY("ldo1", NULL), + REGULATOR_SUPPLY("ldo2", NULL), + REGULATOR_SUPPLY("ldo6", NULL), + REGULATOR_SUPPLY("ldo7", NULL), + REGULATOR_SUPPLY("ldo8", NULL), + REGULATOR_SUPPLY("vcore_audio", NULL), + REGULATOR_SUPPLY("avcore_audio", NULL), + REGULATOR_SUPPLY("vcore1_lpddr2", NULL), + REGULATOR_SUPPLY("vcom_1v8", NULL), + REGULATOR_SUPPLY("pmuio_1v8", NULL), + REGULATOR_SUPPLY("avdd_ic_usb", NULL), +}; + +/* unused */ +static struct regulator_consumer_supply tps6591x_ldo1_supply_0[] = { + REGULATOR_SUPPLY("unused_rail_ldo1", NULL), +}; + +/* EN_+V3.3 switching via FET: +V3.3_AUDIO_AVDD_S, +V3.3 and +V1.8_VDD_LAN + see also v3_3 fixed supply */ +//Apalis T30 +//+V3.3_VPP_FUSE +//POWER_ENABLE_MOCI +//+V3.3_TOUCH_AVDD_S +//+V3.3_AUDIO_AVDD_S +static struct regulator_consumer_supply tps6591x_ldo2_supply_0[] = { + REGULATOR_SUPPLY("en_V3_3", NULL), +}; + +/* +V1.2_CSI */ +static struct regulator_consumer_supply tps6591x_ldo3_supply_0[] = { + REGULATOR_SUPPLY("avdd_dsi_csi", NULL), + REGULATOR_SUPPLY("pwrdet_mipi", NULL), +}; + +/* +V1.2_VDD_RTC */ +static struct regulator_consumer_supply tps6591x_ldo4_supply_0[] = { + REGULATOR_SUPPLY("vdd_rtc", NULL), +}; + +/* +V2.8_AVDD_VDAC */ +//only required for analog RGB +static struct regulator_consumer_supply tps6591x_ldo5_supply_0[] = { + REGULATOR_SUPPLY("avdd_vdac", NULL), +}; + +//Apalis T30 +/* +V1.05_AVDD_PLLE */ +static struct regulator_consumer_supply tps6591x_ldo6_supply_0[] = { + REGULATOR_SUPPLY("avdd_plle", NULL), +}; + +/* +V1.2_AVDD_PLL */ +static struct regulator_consumer_supply tps6591x_ldo7_supply_0[] = { + REGULATOR_SUPPLY("avdd_plla_p_c_s", NULL), + REGULATOR_SUPPLY("avdd_pllm", NULL), + REGULATOR_SUPPLY("avdd_pllu_d", NULL), + REGULATOR_SUPPLY("avdd_pllu_d2", NULL), + REGULATOR_SUPPLY("avdd_pllx", NULL), +}; + +/* +V1.0_VDD_DDR_HS */ +static struct regulator_consumer_supply tps6591x_ldo8_supply_0[] = { + REGULATOR_SUPPLY("vdd_ddr_hs", NULL), +}; + +#define TPS_PDATA_INIT(_name, _sname, _minmv, _maxmv, _supply_reg, _always_on, \ + _boot_on, _apply_uv, _init_uV, _init_enable, _init_apply, _ectrl, _flags) \ + static struct tps6591x_regulator_platform_data pdata_##_name##_##_sname = \ + { \ + .regulator = { \ + .constraints = { \ + .min_uV = (_minmv)*1000, \ + .max_uV = (_maxmv)*1000, \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL | \ + REGULATOR_MODE_STANDBY), \ + .valid_ops_mask = (REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_STATUS | \ + REGULATOR_CHANGE_VOLTAGE), \ + .always_on = _always_on, \ + .boot_on = _boot_on, \ + .apply_uV = _apply_uv, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(tps6591x_##_name##_supply_##_sname), \ + .consumer_supplies = tps6591x_##_name##_supply_##_sname, \ + .supply_regulator = _supply_reg, \ + }, \ + .init_uV = _init_uV * 1000, \ + .init_enable = _init_enable, \ + .init_apply = _init_apply, \ + .ectrl = _ectrl, \ + .flags = _flags, \ + } + +TPS_PDATA_INIT(vdd1, 0, 1350, 1350, 0, 1, 1, 1, -1, 0, 0, 0, 0); +TPS_PDATA_INIT(vdd2, 0, 1050, 1050, 0, 1, 1, 1, -1, 0, 0, EXT_CTRL_SLEEP_OFF, 0); +TPS_PDATA_INIT(vddctrl, 0, 800, 1300, 0, 1, 1, 0, -1, 0, 0, EXT_CTRL_EN1, 0); +TPS_PDATA_INIT(vio, 0, 1800, 1800, 0, 1, 1, 0, -1, 0, 0, 0, 0); + +TPS_PDATA_INIT(ldo1, 0, 1000, 3300, tps6591x_rails(VIO), 0, 0, 0, -1, 0, 1, 0, 0); +/* Make sure EN_+V3.3 is always on! */ +TPS_PDATA_INIT(ldo2, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 1, 0, 0); + +TPS_PDATA_INIT(ldo3, 0, 1200, 1200, 0, 0, 0, 0, -1, 0, 0, 0, 0); +TPS_PDATA_INIT(ldo4, 0, 900, 1400, 0, 1, 0, 0, -1, 0, 0, 0, LDO_LOW_POWER_ON_SUSPEND); +TPS_PDATA_INIT(ldo5, 0, 2800, 2800, 0, 0, 0, 0, -1, 0, 0, 0, 0); +/* AVDD_PLLE should be 1.05V, but ldo_6 can not be adjusted in a 50mV granularity */ +TPS_PDATA_INIT(ldo6, 0, 1000, 1100, tps6591x_rails(VIO), 0, 0, 1, -1, 0, 0, 0, 0); + +TPS_PDATA_INIT(ldo7, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 0, EXT_CTRL_SLEEP_OFF, LDO_LOW_POWER_ON_SUSPEND); +TPS_PDATA_INIT(ldo8, 0, 1000, 1000, tps6591x_rails(VIO), 1, 0, 0, -1, 0, 0, EXT_CTRL_SLEEP_OFF, LDO_LOW_POWER_ON_SUSPEND); + +#if defined(CONFIG_RTC_DRV_TPS6591x) +static struct tps6591x_rtc_platform_data rtc_data = { + .irq = TPS6591X_IRQ_BASE + TPS6591X_INT_RTC_ALARM, + .time = { + .tm_year = 2000, + .tm_mon = 0, + .tm_mday = 1, + .tm_hour = 0, + .tm_min = 0, + .tm_sec = 0, + }, +}; + +#define TPS_RTC_REG() \ + { \ + .id = 0, \ + .name = "rtc_tps6591x", \ + .platform_data = &rtc_data, \ + } +#endif + +#define TPS_REG(_id, _name, _sname) \ + { \ + .id = TPS6591X_ID_##_id, \ + .name = "tps6591x-regulator", \ + .platform_data = &pdata_##_name##_##_sname, \ + } + +static struct tps6591x_subdev_info apalis_t30_tps_devs[] = { + TPS_REG(VDD_1, vdd1, 0), + TPS_REG(VDD_2, vdd2, 0), + TPS_REG(VDDCTRL, vddctrl, 0), + TPS_REG(VIO, vio, 0), + TPS_REG(LDO_1, ldo1, 0), + TPS_REG(LDO_2, ldo2, 0), + TPS_REG(LDO_3, ldo3, 0), + TPS_REG(LDO_4, ldo4, 0), + TPS_REG(LDO_5, ldo5, 0), + TPS_REG(LDO_6, ldo6, 0), + TPS_REG(LDO_7, ldo7, 0), + TPS_REG(LDO_8, ldo8, 0), +#if defined(CONFIG_RTC_DRV_TPS6591x) + TPS_RTC_REG(), +#endif +}; + +static struct tps6591x_sleep_keepon_data tps_slp_keepon = { + .clkout32k_keepon = 1, +}; + +static struct tps6591x_platform_data tps_platform = { + .irq_base = TPS6591X_IRQ_BASE, + .gpio_base = TPS6591X_GPIO_BASE, + .dev_slp_en = true, + .slp_keepon = &tps_slp_keepon, + .use_power_off = true, +}; + +static struct i2c_board_info __initdata apalis_t30_regulators[] = { + { + I2C_BOARD_INFO("tps6591x", 0x2D), +//PWR_INT_IN wake18 + .irq = INT_EXTERNAL_PMU, + .platform_data = &tps_platform, + }, +}; + +/* TPS62362 DC-DC converter + SW: +V1.2_VDD_CORE */ +static struct regulator_consumer_supply tps6236x_dcdc_supply[] = { + REGULATOR_SUPPLY("vdd_core", NULL), +}; + +static struct tps62360_regulator_platform_data tps6236x_pdata = { + .reg_init_data = { \ + .constraints = { \ + .min_uV = 900000, \ + .max_uV = 1400000, \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL | \ + REGULATOR_MODE_STANDBY), \ + .valid_ops_mask = (REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_STATUS | \ + REGULATOR_CHANGE_VOLTAGE), \ + .always_on = 1, \ + .boot_on = 1, \ + .apply_uV = 0, \ + }, \ + .num_consumer_supplies = ARRAY_SIZE(tps6236x_dcdc_supply), \ + .consumer_supplies = tps6236x_dcdc_supply, \ + }, \ + .en_discharge = true, \ + .vsel0_gpio = -1, \ + .vsel1_gpio = -1, \ + .vsel0_def_state = 1, \ + .vsel1_def_state = 1, \ +}; + +static struct i2c_board_info __initdata tps6236x_boardinfo[] = { + { + I2C_BOARD_INFO("tps62360", 0x60), + .platform_data = &tps6236x_pdata, + }, +}; + +/* Macro for defining fixed regulator sub device data */ +#define FIXED_SUPPLY(_name) "fixed_reg_"#_name +#define FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, \ + _boot_on, _gpio_nr, _active_high, _boot_state, \ + _millivolts, _od_state) \ + static struct regulator_init_data ri_data_##_var = \ + { \ + .supply_regulator = _in_supply, \ + .num_consumer_supplies = \ + ARRAY_SIZE(fixed_reg_##_name##_supply), \ + .consumer_supplies = fixed_reg_##_name##_supply, \ + .constraints = { \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL), \ + .valid_ops_mask = (REGULATOR_CHANGE_STATUS), \ + .always_on = _always_on, \ + .boot_on = _boot_on, \ + }, \ + }; \ + static struct fixed_voltage_config fixed_reg_##_var##_pdata = \ + { \ + .supply_name = FIXED_SUPPLY(_name), \ + .microvolts = _millivolts * 1000, \ + .gpio = _gpio_nr, \ + .enable_high = _active_high, \ + .enabled_at_boot = _boot_state, \ + .init_data = &ri_data_##_var, \ + .gpio_is_open_drain = _od_state, \ + }; \ + static struct platform_device fixed_reg_##_var##_dev = { \ + .name = "reg-fixed-voltage", \ + .id = _id, \ + .dev = { \ + .platform_data = &fixed_reg_##_var##_pdata, \ + }, \ + } + +#define FIXED_REG(_id, _var, _name, _in_supply, _always_on, _boot_on, \ + _gpio_nr, _active_high, _boot_state, _millivolts) \ + FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, _boot_on, \ + _gpio_nr, _active_high, _boot_state, _millivolts, false) + +#define ADD_FIXED_REG(_name) (&fixed_reg_##_name##_dev) + +/* PMU GP6: EN_VDD_HDMI switching via FET: +V1.8_AVDD_HDMI_PLL and +V3.3_AVDD_HDMI */ +static struct regulator_consumer_supply fixed_reg_en_hdmi_supply[] = { + REGULATOR_SUPPLY("avdd_hdmi", NULL), + REGULATOR_SUPPLY("avdd_hdmi_pll", NULL), +// REGULATOR_SUPPLY("vdd_3v3_hdmi_cec", NULL), +}; + +//EN_VDD_CORE PMIC GPIO2 +//EN_VDD_FUSE PMIC GPIO4 +//EN_VDD_HDMI PMIC GPIO6 + +FIXED_REG(2, en_hdmi, en_hdmi, NULL, 0, 0, TPS6591X_GPIO_6, true, 1, 1800); + +/* +V3.3 is switched on by LDO2, As this can not be modeled we use a fixed + regulator without enable, 3.3V must not be switched off anyway. ++V3.3: +VDD_DDR_RX +VDDIO_LCD_1 +VDDIO_LCD_2 +VDDIO_CAM +LM95245 +VDDIO_SYS_01 +VDDIO_SYS_02 +VDDIO_BB +VDDIO_AUDIO +VDDIO_GMI_1 +VDDIO_GMI_2 +VDDIO_GMI_3 +VDDIO_UART +VDDIO_SDMMC1 +AVDD_USB +VDDIO_SDMMC3 +74AVCAH164245 +VDDIO_PEX_CTL +TPS65911 VDDIO +MT29F16G08 +SGTL5000 VDDIO +STMPE811 +AX88772B VCC3x +SDIN5D2-2G VCCx */ +static struct regulator_consumer_supply fixed_reg_v3_3_supply[] = { + REGULATOR_SUPPLY("avdd_audio", NULL), + REGULATOR_SUPPLY("avdd_usb", NULL), + REGULATOR_SUPPLY("vddio_sd_slot", "sdhci-tegra.1"), + REGULATOR_SUPPLY("vddio_sys", NULL), + REGULATOR_SUPPLY("vddio_uart", NULL), + REGULATOR_SUPPLY("pwrdet_uart", NULL), + REGULATOR_SUPPLY("vddio_audio", NULL), + REGULATOR_SUPPLY("pwrdet_audio", NULL), + REGULATOR_SUPPLY("vddio_bb", NULL), + REGULATOR_SUPPLY("pwrdet_bb", NULL), + REGULATOR_SUPPLY("vddio_lcd_pmu", NULL), + REGULATOR_SUPPLY("pwrdet_lcd", NULL), + REGULATOR_SUPPLY("vddio_cam", NULL), + REGULATOR_SUPPLY("pwrdet_cam", NULL), + /* if this supply is defined, the sdhci driver tries + * to set it to 1.8V */ +// REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.1"), + REGULATOR_SUPPLY("pwrdet_sdmmc2", NULL), + REGULATOR_SUPPLY("pwrdet_sdmmc1", NULL), + REGULATOR_SUPPLY("pwrdet_sdmmc3", NULL), + REGULATOR_SUPPLY("pwrdet_pex_ctl", NULL), + REGULATOR_SUPPLY("pwrdet_nand", NULL), + + /* SGTL5000 */ + REGULATOR_SUPPLY("VDDA", "4-000a"), + REGULATOR_SUPPLY("VDDIO", "4-000a"), + + REGULATOR_SUPPLY("hvdd_pex", NULL), + REGULATOR_SUPPLY("hvdd_sata", NULL), +}; + +FIXED_REG(3, v3_3, v3_3, NULL, 1, 1, -1, true, 1, 3300); + +/* Gpio switch regulator platform data */ +static struct platform_device *fixed_reg_devs_apalis_t30[] = { + ADD_FIXED_REG(en_hdmi), + ADD_FIXED_REG(v3_3), +}; + +int __init apalis_t30_regulator_init(void) +{ + void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); + u32 pmc_ctrl; + + /* configure the power management controller to trigger PMU + * interrupts when low */ + + pmc_ctrl = readl(pmc + PMC_CTRL); + writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL); + + /* The regulator details have complete constraints */ + regulator_has_full_constraints(); + + tps_platform.num_subdevs = + ARRAY_SIZE(apalis_t30_tps_devs); + tps_platform.subdevs = apalis_t30_tps_devs; + + i2c_register_board_info(4, apalis_t30_regulators, 1); + + /* Register the TPS6236x. */ + pr_info("Registering the device TPS62360\n"); + i2c_register_board_info(4, tps6236x_boardinfo, 1); + + return 0; +} + +int __init apalis_t30_fixed_regulator_init(void) +{ + return platform_add_devices(fixed_reg_devs_apalis_t30, ARRAY_SIZE(fixed_reg_devs_apalis_t30)); +} +subsys_initcall_sync(apalis_t30_fixed_regulator_init); + +static void apalis_t30_board_suspend(int lp_state, enum suspend_stage stg) +{ + if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_SUSPEND_BEFORE_CPU)) + tegra_console_uart_suspend(); +} + +static void apalis_t30_board_resume(int lp_state, enum resume_stage stg) +{ + if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_RESUME_AFTER_CPU)) + tegra_console_uart_resume(); +} + +static struct tegra_suspend_platform_data apalis_t30_suspend_data = { + .cpu_timer = 2000, + .cpu_off_timer = 200, + .suspend_mode = TEGRA_SUSPEND_LP1, + .core_timer = 0x7e7e, + .core_off_timer = 0, + .corereq_high = true, + .sysclkreq_high = true, + .cpu_lp2_min_residency = 2000, + .board_suspend = apalis_t30_board_suspend, + .board_resume = apalis_t30_board_resume, +}; + +int __init apalis_t30_suspend_init(void) +{ + /* Make core_pwr_req to high */ + apalis_t30_suspend_data.corereq_high = true; + + /* CORE_PWR_REQ to be high required to enable the dc-dc converter tps62361x */ + apalis_t30_suspend_data.corereq_high = true; + +//required? + apalis_t30_suspend_data.cpu_timer = 5000; + apalis_t30_suspend_data.cpu_off_timer = 5000; + + tegra_init_suspend(&apalis_t30_suspend_data); + return 0; +} + +#ifdef CONFIG_TEGRA_EDP_LIMITS +int __init apalis_t30_edp_init(void) +{ + unsigned int regulator_mA; + + regulator_mA = get_maximum_cpu_current_supported(); + if (!regulator_mA) { + regulator_mA = 6000; /* regular T30/s */ + } + pr_info("%s: CPU regulator %d mA\n", __func__, regulator_mA); + + tegra_init_cpu_edp_limits(regulator_mA); + return 0; +} +#endif diff --git a/arch/arm/mach-tegra/board-apalis_t30.c b/arch/arm/mach-tegra/board-apalis_t30.c new file mode 100644 index 000000000000..f7340b91eb8d --- /dev/null +++ b/arch/arm/mach-tegra/board-apalis_t30.c @@ -0,0 +1,1432 @@ +/* + * arch/arm/mach-tegra/board-apalis_t30.c + * + * Copyright (c) 2013 Toradex, Inc. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <linux/can/platform/mcp251x.h> +#include <linux/clk.h> +#include <linux/types.h> /* required by linux/gpio_keys.h */ +#include <linux/gpio_keys.h> +#include <linux/i2c.h> +#include <linux/i2c-tegra.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/leds_pwm.h> +#include <linux/lm95245.h> +#include <linux/mfd/stmpe.h> +#include <linux/platform_data/tegra_usb.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/spi/spi.h> +#include <linux/spi-tegra.h> +#include <linux/tegra_uart.h> + +#include <mach/io_dpd.h> +#include <mach/pci.h> +#include <mach/sdhci.h> +#include <mach/tegra_asoc_pdata.h> +#include <mach/tegra_fiq_debugger.h> +#include <mach/thermal.h> +#include <mach/usb_phy.h> +#include <mach/w1.h> + +#include <media/soc_camera.h> +#include <media/tegra_v4l2_camera.h> +#include <linux/input/fusion_F0710A.h> + +#include "board-apalis_t30.h" +#include "board.h" +#include "clock.h" +#include "devices.h" +#include "gpio-names.h" +#include "pm.h" +#include "wakeups-t3.h" + +/* ADC */ + +//TODO + +/* Audio */ + +/* HDA */ + +//TODO + +/* I2S */ + +static struct tegra_asoc_platform_data apalis_t30_audio_sgtl5000_pdata = { + .gpio_spkr_en = -1, + .gpio_hp_det = -1, + .gpio_hp_mute = -1, + .gpio_int_mic_en = -1, + .gpio_ext_mic_en = -1, + .i2s_param[HIFI_CODEC] = { + .audio_port_id = 1, /* index of below registered + tegra_i2s_device plus one if HDA codec + is activated as well */ + .i2s_mode = TEGRA_DAIFMT_I2S, + .is_i2s_master = 1, + .sample_size = 16, + }, + .i2s_param[BASEBAND] = { + .audio_port_id = -1, + }, + .i2s_param[BT_SCO] = { + .audio_port_id = -1, + }, +}; + +static struct platform_device apalis_t30_audio_sgtl5000_device = { + .name = "tegra-snd-colibri_t30-sgtl5000", + .id = 0, + .dev = { + .platform_data = &apalis_t30_audio_sgtl5000_pdata, + }, +}; + +/* Camera */ + +#ifdef CONFIG_TEGRA_CAMERA +static struct platform_device tegra_camera = { + .name = "tegra_camera", + .id = -1, +}; +#endif /* CONFIG_TEGRA_CAMERA */ + +#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE) +static void tegra_camera_disable(struct nvhost_device *ndev) +{ +} + +static int tegra_camera_enable(struct nvhost_device *ndev) +{ + return 0; +} + +static struct tegra_camera_platform_data tegra_camera_platform_data = { + .disable_camera = tegra_camera_disable, + .enable_camera = tegra_camera_enable, + .flip_h = 0, + .flip_v = 0, + .port = TEGRA_CAMERA_PORT_VIP, +}; + +#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE) +static struct i2c_board_info camera_i2c_max9526 = { + I2C_BOARD_INFO("max9526", 0x20), +}; + +static struct soc_camera_link iclink_max9526 = { + .board_info = &camera_i2c_max9526, + .bus_id = -1, /* This must match the .id of tegra_vi01_device */ + .i2c_adapter_id = 2, +}; + +static struct platform_device soc_camera_max9526 = { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &iclink_max9526, + }, +}; +#endif /* CONFIG_SOC_CAMERA_MAX9526 | CONFIG_SOC_CAMERA_MAX9526_MODULE */ + +#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE) +static struct i2c_board_info camera_i2c_adv7180 = { + I2C_BOARD_INFO("adv7180", 0x21), +}; + +static struct soc_camera_link iclink_adv7180 = { + .board_info = &camera_i2c_adv7180, + .bus_id = -1, /* This must match the .id of tegra_vi01_device */ + .i2c_adapter_id = 2, +}; + +static struct platform_device soc_camera_adv7180 = { + .name = "soc-camera-pdrv", + .id = 1, + .dev = { + .platform_data = &iclink_adv7180, + }, +}; +#endif /* CONFIG_VIDEO_ADV7180 | CONFIG_VIDEO_ADV7180_MODULE */ +#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */ + +/* CAN */ + +#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE) +static struct mcp251x_platform_data can_pdata = { + .oscillator_frequency = 16000000, + .power_enable = NULL, + .transceiver_enable = NULL +}; + +static struct spi_board_info can_board_info[] = { + { + .bus_num = 1, /* SPI2: CAN1 */ + .chip_select = 0, + .max_speed_hz = 10000000, + .modalias = "mcp2515", + .platform_data = &can_pdata, + }, + { + .bus_num = 3, /* SPI4: CAN2 */ + .chip_select = 1, + .max_speed_hz = 10000000, + .modalias = "mcp2515", + .platform_data = &can_pdata, + }, +}; + +static void __init apalis_t30_mcp2515_can_init(void) +{ + can_board_info[0].irq = gpio_to_irq(CAN1_INT); + can_board_info[1].irq = gpio_to_irq(CAN2_INT); + spi_register_board_info(can_board_info, ARRAY_SIZE(can_board_info)); +} +#else /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */ +#define apalis_t30_mcp2515_can_init() do {} while (0) +#endif /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */ + +/* CEC */ + +//TODO + +/* Clocks */ +static struct tegra_clk_init_table apalis_t30_clk_init_table[] __initdata = { + /* name parent rate enabled */ + {"audio1", "i2s1_sync", 0, false}, + {"audio2", "i2s2_sync", 0, false}, + {"audio3", "i2s3_sync", 0, false}, + {"blink", "clk_32k", 32768, true}, + {"d_audio", "clk_m", 12000000, false}, + {"dam0", "clk_m", 12000000, false}, + {"dam1", "clk_m", 12000000, false}, + {"dam2", "clk_m", 12000000, false}, + {"hda", "pll_p", 108000000, false}, + {"hda2codec_2x","pll_p", 48000000, false}, + {"i2c1", "pll_p", 3200000, false}, + {"i2c2", "pll_p", 3200000, false}, + {"i2c3", "pll_p", 3200000, false}, + {"i2c4", "pll_p", 3200000, false}, + {"i2c5", "pll_p", 3200000, false}, + {"i2s0", "pll_a_out0", 0, false}, + {"i2s1", "pll_a_out0", 0, false}, + {"i2s2", "pll_a_out0", 0, false}, + {"i2s3", "pll_a_out0", 0, false}, + {"pll_a", NULL, 564480000, true}, + {"pll_m", NULL, 0, false}, + {"pwm", "pll_p", 3187500, false}, + {"spdif_out", "pll_a_out0", 0, false}, + {"vi", "pll_p", 0, false}, + {"vi_sensor", "pll_p", 150000000, false}, + {NULL, NULL, 0, 0}, +}; + +/* GPIO */ + +static struct gpio apalis_t30_gpios[] = { + {APALIS_GPIO1, GPIOF_IN, "GPIO1 X1-1"}, + {APALIS_GPIO2, GPIOF_IN, "GPIO2 X1-3"}, + {APALIS_GPIO3, GPIOF_IN, "GPIO3 X1-5"}, + {APALIS_GPIO4, GPIOF_IN, "GPIO4 X1-7"}, + {APALIS_GPIO5, GPIOF_IN, "GPIO5 X1-9"}, + {APALIS_GPIO6, GPIOF_IN, "GPIO6 X1-11"}, + /* GPIO7 is used by PCIe driver on Evaluation board */ +/* {APALIS_GPIO7, GPIOF_IN, "GPIO7 X1-13"}, */ + {APALIS_GPIO8, GPIOF_IN, "GPIO8 X1-15, FAN"}, + {LVDS_MODE, GPIOF_IN, "LVDS: Single/Dual Ch"}, + {LVDS_6B_8B_N, GPIOF_IN, "LVDS: 18/24 Bit Mode"}, + {LVDS_OE, GPIOF_IN, "LVDS: Output Enable"}, + {LVDS_PDWN_N, GPIOF_IN, "LVDS: Power Down"}, + {LVDS_R_F_N, GPIOF_IN, "LVDS: Clock Polarity"}, + {LVDS_MAP, GPIOF_IN, "LVDS: Colour Mapping"}, + {LVDS_RS, GPIOF_IN, "LVDS: Swing Mode"}, + {LVDS_DDR_N, GPIOF_IN, "LVDS: DDRclk Disable"}, +}; + +static void apalis_t30_gpio_init(void) +{ + int i = 0; + int length = sizeof(apalis_t30_gpios) / sizeof(struct gpio); + int err = 0; + + for (i = 0; i < length; i++) { + err = gpio_request_one(apalis_t30_gpios[i].gpio, + apalis_t30_gpios[i].flags, + apalis_t30_gpios[i].label); + + if (err) { + pr_warning("gpio_request(%s) failed, err = %d", + apalis_t30_gpios[i].label, err); + } else { + gpio_export(apalis_t30_gpios[i].gpio, true); + } + } +} + + +/* + * Fusion touch screen GPIOs (using Toradex display/touch adapater) + * Apalis GPIO 5, MXM-11, Ixora X27-17, pen down interrupt + * Apalis GPIO 6, MXM-13, Ixora X27-18, reset + * gpio_request muxes the GPIO function automatically, we only have to make + * sure input/output muxing is done and the GPIO is freed here. + */ +static int pinmux_fusion_pins(void); + +static struct fusion_f0710a_init_data apalis_fusion_pdata = { + .pinmux_fusion_pins = &pinmux_fusion_pins, + .gpio_int = APALIS_GPIO5, /* MXM-11, Pen down interrupt */ + .gpio_reset = APALIS_GPIO6, /* MXM-13, Reset interrupt */ +}; + +static int pinmux_fusion_pins(void) +{ + gpio_free(apalis_fusion_pdata.gpio_int); + gpio_free(apalis_fusion_pdata.gpio_reset); + apalis_fusion_pdata.pinmux_fusion_pins = NULL; + return 0; +} + +/* I2C */ + +/* Make sure that the pinmuxing enable the 'open drain' feature for pins used + for I2C */ + +/* GEN1_I2C: I2C1_SDA/SCL on MXM3 pin 209/211 (e.g. RTC on carrier board) */ +static struct i2c_board_info apalis_t30_i2c_bus1_board_info[] __initdata = { + { + /* M41T0M6 real time clock on Iris carrier board */ + I2C_BOARD_INFO("rtc-ds1307", 0x68), + .type = "m41t00", + }, + { + /* TouchRevolution Fusion 7 and 10 multi-touch controller */ + I2C_BOARD_INFO("fusion_F0710A", 0x10), + .platform_data = &apalis_fusion_pdata, + }, +}; + +static struct tegra_i2c_platform_data apalis_t30_i2c1_platform_data = { + .adapter_nr = 0, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {400000, 0}, + .bus_count = 1, + .scl_gpio = {I2C1_SCL, 0}, + .sda_gpio = {I2C1_SDA, 0}, + .slave_addr = 0x00FC, +}; + +/* GEN2_I2C: unused */ + +/* DDC: I2C2_SDA/SCL on MXM3 pin 205/207 (e.g. display EDID) */ +static struct tegra_i2c_platform_data apalis_t30_i2c4_platform_data = { + .adapter_nr = 3, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {10000, 10000}, + .bus_count = 1, + .scl_gpio = {I2C2_SCL, 0}, + .sda_gpio = {I2C2_SDA, 0}, + .slave_addr = 0x00FC, +}; + +/* CAM_I2C: I2C3_SDA/SCL on MXM3 pin 201/203 (e.g. camera sensor on carrier + board) */ +static struct tegra_i2c_platform_data apalis_t30_i2c3_platform_data = { + .adapter_nr = 2, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {400000, 0}, + .bus_count = 1, + .scl_gpio = {I2C3_SCL, 0}, + .sda_gpio = {I2C3_SDA, 0}, + .slave_addr = 0x00FC, +}; + +/* PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and touch screen + controller */ + +/* STMPE811 touch screen controller */ +static struct stmpe_ts_platform_data stmpe811_ts_data = { + .adc_freq = 1, /* 3.25 MHz ADC clock speed */ + .ave_ctrl = 3, /* 8 sample average control */ + .fraction_z = 7, /* 7 length fractional part in z */ + .i_drive = 1, /* 50 mA typical 80 mA max touchscreen + drivers current limit value */ + .mod_12b = 1, /* 12-bit ADC */ + .ref_sel = 0, /* internal ADC reference */ + .sample_time = 4, /* ADC converstion time: 80 clocks */ + .settling = 3, /* 1 ms panel driver settling time */ + .touch_det_delay = 5, /* 5 ms touch detect interrupt delay */ +}; + +/* STMPE811 ADC controller */ +static struct stmpe_adc_platform_data stmpe811_adc_data = { + .sample_time = 4, /* ADC converstion time: 80 clocks */ + .mod_12b = 1, /* 12-bit ADC */ + .ref_sel = 0, /* internal ADC reference */ + .adc_freq = 1, /* 3.25 MHz ADC clock speed */ +}; + +static struct stmpe_platform_data stmpe811_data = { + .blocks = STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC, + .id = 1, + .irq_base = STMPE811_IRQ_BASE, + .irq_trigger = IRQF_TRIGGER_FALLING, + .ts = &stmpe811_ts_data, + .adc = &stmpe811_adc_data, +}; + +static void lm95245_probe_callback(struct device *dev); + +static struct lm95245_platform_data apalis_t30_lm95245_pdata = { + .enable_os_pin = true, + .probe_callback = lm95245_probe_callback, +}; + +static struct i2c_board_info apalis_t30_i2c_bus5_board_info[] __initdata = { + { + /* SGTL5000 audio codec */ + I2C_BOARD_INFO("sgtl5000", 0x0a), + }, + { + /* STMPE811 touch screen controller */ + I2C_BOARD_INFO("stmpe", 0x41), + .flags = I2C_CLIENT_WAKE, + .platform_data = &stmpe811_data, + .type = "stmpe811", + }, + { + /* LM95245 temperature sensor + Note: OVERT_N directly connected to PMIC PWRDN */ + I2C_BOARD_INFO("lm95245", 0x4c), + .platform_data = &apalis_t30_lm95245_pdata, + }, +}; + +static struct tegra_i2c_platform_data apalis_t30_i2c5_platform_data = { + .adapter_nr = 4, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {400000, 0}, + .bus_count = 1, + .scl_gpio = {PWR_I2C_SCL, 0}, + .sda_gpio = {PWR_I2C_SDA, 0}, +}; + +static void __init apalis_t30_i2c_init(void) +{ + tegra_i2c_device1.dev.platform_data = &apalis_t30_i2c1_platform_data; + tegra_i2c_device3.dev.platform_data = &apalis_t30_i2c3_platform_data; + tegra_i2c_device4.dev.platform_data = &apalis_t30_i2c4_platform_data; + tegra_i2c_device5.dev.platform_data = &apalis_t30_i2c5_platform_data; + + platform_device_register(&tegra_i2c_device1); + platform_device_register(&tegra_i2c_device3); + platform_device_register(&tegra_i2c_device4); + platform_device_register(&tegra_i2c_device5); + + i2c_register_board_info(0, apalis_t30_i2c_bus1_board_info, + ARRAY_SIZE(apalis_t30_i2c_bus1_board_info)); + + /* enable touch interrupt GPIO */ + gpio_request(TOUCH_PEN_INT, "TOUCH_PEN_INT"); + gpio_direction_input(TOUCH_PEN_INT); + + apalis_t30_i2c_bus5_board_info[1].irq = gpio_to_irq(TOUCH_PEN_INT); + i2c_register_board_info(4, apalis_t30_i2c_bus5_board_info, + ARRAY_SIZE(apalis_t30_i2c_bus5_board_info)); +} + +/* IrDA */ + +//TODO + +/* Keys + * Note: active-low means pull-ups required on carrier board resp. via + * pin-muxing + * Note2: power-key active-high due to EvalBoard v3.1a having 100 K pull-down + * on SODIMM pin 45 + * Note3: menu-key active-high due to strong pull-down on multiplexed + * ACC1_DETECT + * Note4: Wake keys need to be supported by hardware, see wakeups-t3.h + */ + +#ifdef CONFIG_KEYBOARD_GPIO +#define GPIO_KEY(_id, _gpio, _lowactive, _iswake) \ + { \ + .code = _id, \ + .gpio = TEGRA_GPIO_##_gpio, \ + .active_low = _lowactive, \ + .desc = #_id, \ + .type = EV_KEY, \ + .wakeup = _iswake, \ + .debounce_interval = 10, \ + } + +static struct gpio_keys_button apalis_t30_keys[] = { + GPIO_KEY(KEY_POWER, PV1, 0, 1), /* SODIMM pin 45, Iris X16-20/EvalBoard X3 B24 */ +}; + +#define PMC_WAKE_STATUS 0x14 + +static int apalis_t30_wakeup_key(void) +{ + unsigned long status = + readl(IO_ADDRESS(TEGRA_PMC_BASE) + PMC_WAKE_STATUS); + + return (status & (1 << TEGRA_WAKE_GPIO_PV1)) ? + KEY_POWER : KEY_RESERVED; +} + +static struct gpio_keys_platform_data apalis_t30_keys_platform_data = { + .buttons = apalis_t30_keys, + .nbuttons = ARRAY_SIZE(apalis_t30_keys), + .wakeup_key = apalis_t30_wakeup_key, +}; + +static struct platform_device apalis_t30_keys_device = { + .name = "gpio-keys", + .id = 0, + .dev = { + .platform_data = &apalis_t30_keys_platform_data, + }, +}; +#endif /* CONFIG_KEYBOARD_GPIO */ + +/* MMC/SD */ + +static struct tegra_sdhci_platform_data apalis_t30_emmc_platform_data = { + .cd_gpio = -1, + .ddr_clk_limit = 52000000, + .is_8bit = 1, + .mmc_data = { + .built_in = 1, + }, + .power_gpio = -1, + .tap_delay = 0x0f, + .wp_gpio = -1, +}; + +static struct tegra_sdhci_platform_data apalis_t30_mmccard_platform_data = { + .cd_gpio = MMC1_CD_N, + .ddr_clk_limit = 52000000, + .is_8bit = 1, + .power_gpio = -1, + .tap_delay = 0x0f, + .wp_gpio = -1, +}; + +static struct tegra_sdhci_platform_data apalis_t30_sdcard_platform_data = { + .cd_gpio = SD1_CD_N, + .ddr_clk_limit = 52000000, + .is_8bit = 0, + .power_gpio = -1, + .tap_delay = 0x0f, + .wp_gpio = -1, +}; + +static void __init apalis_t30_sdhci_init(void) +{ + /* register eMMC first */ + tegra_sdhci_device4.dev.platform_data = + &apalis_t30_emmc_platform_data; + platform_device_register(&tegra_sdhci_device4); + + tegra_sdhci_device3.dev.platform_data = + &apalis_t30_mmccard_platform_data; + platform_device_register(&tegra_sdhci_device3); + + tegra_sdhci_device1.dev.platform_data = + &apalis_t30_sdcard_platform_data; + platform_device_register(&tegra_sdhci_device1); +} + +/* PCIe */ + +/* The Apalis evaluation board needs to set the link speed to 2.5 GT/s (GEN1). + The default link speed setting is 5 GT/s (GEN2). 0x98 is the Link Control 2 + PCIe Capability Register of the PEX8605 PCIe switch. The switch supports + link speed auto negotiation, but falsely sets the link speed to 5 GT/s. */ +static void __devinit quirk_apalis_plx_gen1(struct pci_dev *dev) +{ + pci_write_config_dword(dev, 0x98, 0x01); + mdelay(50); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8605, quirk_apalis_plx_gen1); + +static struct tegra_pci_platform_data apalis_t30_pci_platform_data = { + .port_status[0] = 1, + .port_status[1] = 1, + .port_status[2] = 1, + .use_dock_detect = 0, + .gpio = 0, +}; + +static void apalis_t30_pci_init(void) +{ + /* Reset PLX PEX 8605 PCIe Switch plus PCIe devices on Apalis Evaluation + Board */ + gpio_request(PEX_PERST_N, "PEX_PERST_N"); + gpio_request(RESET_MOCI_N, "RESET_MOCI_N"); + gpio_direction_output(PEX_PERST_N, 0); + gpio_direction_output(RESET_MOCI_N, 0); + /* Must be asserted for 100 ms after power and clocks are stable */ + msleep(100); + gpio_set_value(PEX_PERST_N, 1); + /* Err_5: PEX_REFCLK_OUTpx/nx Clock Outputs is not Guaranteed Until + 900 us After PEX_PERST# De-assertion */ + msleep(1); + gpio_set_value(RESET_MOCI_N, 1); + + tegra_pci_device.dev.platform_data = &apalis_t30_pci_platform_data; + platform_device_register(&tegra_pci_device); +} + +/* PWM LEDs */ +static struct led_pwm tegra_leds_pwm[] = { + { + .name = "PWM3", + .pwm_id = 1, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, + { + .name = "PWM2", + .pwm_id = 2, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, + { + .name = "PWM1", + .pwm_id = 3, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, +}; + +static struct led_pwm_platform_data tegra_leds_pwm_data = { + .num_leds = ARRAY_SIZE(tegra_leds_pwm), + .leds = tegra_leds_pwm, +}; + +static struct platform_device tegra_led_pwm_device = { + .name = "leds_pwm", + .id = -1, + .dev = { + .platform_data = &tegra_leds_pwm_data, + }, +}; + +/* RTC */ + +#ifdef CONFIG_RTC_DRV_TEGRA +static struct resource tegra_rtc_resources[] = { + [0] = { + .start = TEGRA_RTC_BASE, + .end = TEGRA_RTC_BASE + TEGRA_RTC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_RTC, + .end = INT_RTC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device tegra_rtc_device = { + .name = "tegra_rtc", + .id = -1, + .resource = tegra_rtc_resources, + .num_resources = ARRAY_SIZE(tegra_rtc_resources), +}; +#endif /* CONFIG_RTC_DRV_TEGRA */ + +/* SATA */ + +#ifdef CONFIG_SATA_AHCI_TEGRA +static struct gpio_led apalis_gpio_leds[] = { + [0] = { + .name = "SATA1_ACT_N", + .default_trigger = "ide-disk", + .gpio = SATA1_ACT_N, + .active_low = 1, + .retain_state_suspended = 0, + }, +}; + +static struct gpio_led_platform_data apalis_gpio_led_data = { + .num_leds = ARRAY_SIZE(apalis_gpio_leds), + .leds = apalis_gpio_leds, +}; + +static struct platform_device apalis_led_gpio_device = { + .name = "leds-gpio", + .dev = { + .platform_data = &apalis_gpio_led_data, + }, +}; + +static void apalis_t30_sata_init(void) +{ + platform_device_register(&tegra_sata_device); + platform_device_register(&apalis_led_gpio_device); +} +#else +static void apalis_t30_sata_init(void) { } +#endif + +/* SPI */ + +#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV) +static struct spi_board_info tegra_spi_devices[] __initdata = { + { + .bus_num = 0, /* SPI1: Apalis SPI1 */ + .chip_select = 0, + .irq = 0, + .max_speed_hz = 50000000, + .modalias = "spidev", + .mode = SPI_MODE_0, + .platform_data = NULL, + }, + { + .bus_num = 4, /* SPI5: Apalis SPI2 */ + .chip_select = 2, + .irq = 0, + .max_speed_hz = 50000000, + .modalias = "spidev", + .mode = SPI_MODE_0, + .platform_data = NULL, + }, +}; + +static void __init apalis_t30_register_spidev(void) +{ + spi_register_board_info(tegra_spi_devices, + ARRAY_SIZE(tegra_spi_devices)); +} +#else /* CONFIG_SPI_TEGRA && CONFIG_SPI_SPIDEV */ +#define apalis_t30_register_spidev() do {} while (0) +#endif /* CONFIG_SPI_TEGRA && CONFIG_SPI_SPIDEV */ + +static struct platform_device *apalis_t30_spi_devices[] __initdata = { + &tegra_spi_device1, + &tegra_spi_device2, + &tegra_spi_device4, + &tegra_spi_device5, +}; + +static struct spi_clk_parent spi_parent_clk[] = { + [0] = {.name = "pll_p"}, +#ifndef CONFIG_TEGRA_PLLM_RESTRICTED + [1] = {.name = "pll_m"}, + [2] = {.name = "clk_m"}, +#else /* !CONFIG_TEGRA_PLLM_RESTRICTED */ + [1] = {.name = "clk_m"}, +#endif /* !CONFIG_TEGRA_PLLM_RESTRICTED */ +}; + +static struct tegra_spi_platform_data apalis_t30_spi_pdata = { + .is_dma_based = true, + .max_dma_buffer = 16 * 1024, + .is_clkon_always = false, + .max_rate = 100000000, +}; + +static void __init apalis_t30_spi_init(void) +{ + int i; + struct clk *c; + + for (i = 0; i < ARRAY_SIZE(spi_parent_clk); ++i) { + c = tegra_get_clock_by_name(spi_parent_clk[i].name); + if (IS_ERR_OR_NULL(c)) { + pr_err("Not able to get the clock for %s\n", + spi_parent_clk[i].name); + continue; + } + spi_parent_clk[i].parent_clk = c; + spi_parent_clk[i].fixed_clk_rate = clk_get_rate(c); + } + apalis_t30_spi_pdata.parent_clk_list = spi_parent_clk; + apalis_t30_spi_pdata.parent_clk_count = ARRAY_SIZE(spi_parent_clk); + tegra_spi_device1.dev.platform_data = &apalis_t30_spi_pdata; + platform_add_devices(apalis_t30_spi_devices, + ARRAY_SIZE(apalis_t30_spi_devices)); +} + +/* Thermal throttling */ + +static void *apalis_t30_alert_data; +static void (*apalis_t30_alert_func)(void *); +static int apalis_t30_low_edge = 0; +static int apalis_t30_low_hysteresis = 3000; +static int apalis_t30_low_limit = 0; +static struct device *lm95245_device = NULL; +static int thermd_alert_irq_disabled = 0; +struct work_struct thermd_alert_work; +struct workqueue_struct *thermd_alert_workqueue; + +static struct balanced_throttle throttle_list[] = { +#ifdef CONFIG_TEGRA_THERMAL_THROTTLE + { + .id = BALANCED_THROTTLE_ID_TJ, + .throt_tab_size = 10, + .throt_tab = { + { 0, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 760000, 1000 }, + { 760000, 1050 }, + {1000000, 1050 }, + {1000000, 1100 }, + }, + }, +#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */ +#ifdef CONFIG_TEGRA_SKIN_THROTTLE + { + .id = BALANCED_THROTTLE_ID_SKIN, + .throt_tab_size = 6, + .throt_tab = { + { 640000, 1200 }, + { 640000, 1200 }, + { 760000, 1200 }, + { 760000, 1200 }, + {1000000, 1200 }, + {1000000, 1200 }, + }, + }, +#endif /* CONFIG_TEGRA_SKIN_THROTTLE */ +}; + +/* All units are in millicelsius */ +static struct tegra_thermal_data thermal_data = { + .shutdown_device_id = THERMAL_DEVICE_ID_NCT_EXT, + .temp_shutdown = 115000, + +#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE) + .throttle_edp_device_id = THERMAL_DEVICE_ID_NCT_EXT, +#endif +#ifdef CONFIG_TEGRA_EDP_LIMITS + .edp_offset = TDIODE_OFFSET, /* edp based on tdiode */ + .hysteresis_edp = 3000, +#endif +#ifdef CONFIG_TEGRA_THERMAL_THROTTLE + .temp_throttle = 85000, + .tc1 = 0, + .tc2 = 1, + .passive_delay = 2000, +#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */ +#ifdef CONFIG_TEGRA_SKIN_THROTTLE + .skin_device_id = THERMAL_DEVICE_ID_SKIN, + .temp_throttle_skin = 43000, + .tc1_skin = 0, + .tc2_skin = 1, + .passive_delay_skin = 5000, + + .skin_temp_offset = 9793, + .skin_period = 1100, + .skin_devs_size = 2, + .skin_devs = { + { + THERMAL_DEVICE_ID_NCT_EXT, + { + 2, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 0, + 1, 1, 0, 0, + 0, 0, -1, -7 + } + }, + { + THERMAL_DEVICE_ID_NCT_INT, + { + -11, -7, -5, -3, + -3, -2, -1, 0, + 0, 0, 1, 1, + 1, 2, 2, 3, + 4, 6, 11, 18 + } + }, + }, +#endif /* CONFIG_TEGRA_SKIN_THROTTLE */ +}; + +/* Over-temperature shutdown OS aka high limit GPIO pin interrupt handler */ +static irqreturn_t thermd_alert_irq(int irq, void *data) +{ + disable_irq_nosync(irq); + thermd_alert_irq_disabled = 1; + queue_work(thermd_alert_workqueue, &thermd_alert_work); + + return IRQ_HANDLED; +} + +/* Gets both entered by THERMD_ALERT GPIO interrupt as well as re-scheduled. */ +static void thermd_alert_work_func(struct work_struct *work) +{ + int temp = 0; + + lm95245_get_remote_temp(lm95245_device, &temp); + + /* This emulates NCT1008 low limit behaviour */ + if (!apalis_t30_low_edge && temp <= apalis_t30_low_limit) { + apalis_t30_alert_func(apalis_t30_alert_data); + apalis_t30_low_edge = 1; + } else if (apalis_t30_low_edge && temp > apalis_t30_low_limit + + apalis_t30_low_hysteresis) { + apalis_t30_low_edge = 0; + } + + /* Avoid unbalanced enable for IRQ 367 */ + if (thermd_alert_irq_disabled) { + apalis_t30_alert_func(apalis_t30_alert_data); + thermd_alert_irq_disabled = 0; + enable_irq(gpio_to_irq(THERMD_ALERT_N)); + } + + /* Keep re-scheduling */ + msleep(2000); + queue_work(thermd_alert_workqueue, &thermd_alert_work); +} + +static int lm95245_get_temp(void *_data, long *temp) +{ + struct device *lm95245_device = _data; + int lm95245_temp = 0; + lm95245_get_remote_temp(lm95245_device, &lm95245_temp); + *temp = lm95245_temp; + return 0; +} + +static int lm95245_get_temp_low(void *_data, long *temp) +{ + *temp = 0; + return 0; +} + +/* Our temperature sensor only allows triggering an interrupt on over- + temperature shutdown aka the high limit we therefore need to setup a + workqueue to catch leaving the low limit. */ +static int lm95245_set_limits(void *_data, + long lo_limit_milli, + long hi_limit_milli) +{ + struct device *lm95245_device = _data; + apalis_t30_low_limit = lo_limit_milli; + if (lm95245_device) lm95245_set_remote_os_limit(lm95245_device, + hi_limit_milli); + return 0; +} + +static int lm95245_set_alert(void *_data, + void (*alert_func)(void *), + void *alert_data) +{ + lm95245_device = _data; + apalis_t30_alert_func = alert_func; + apalis_t30_alert_data = alert_data; + return 0; +} + +static int lm95245_set_shutdown_temp(void *_data, long shutdown_temp) +{ + struct device *lm95245_device = _data; + if (lm95245_device) lm95245_set_remote_critical_limit(lm95245_device, + shutdown_temp); + return 0; +} + +#ifdef CONFIG_TEGRA_SKIN_THROTTLE +/* Internal aka local board/case temp */ +static int lm95245_get_itemp(void *dev_data, long *temp) +{ + struct device *lm95245_device = dev_data; + int lm95245_temp = 0; + lm95245_get_local_temp(lm95245_device, &lm95245_temp); + *temp = lm95245_temp; + return 0; +} +#endif /* CONFIG_TEGRA_SKIN_THROTTLE */ + +static void lm95245_probe_callback(struct device *dev) +{ + struct tegra_thermal_device *lm95245_remote; + + lm95245_remote = kzalloc(sizeof(struct tegra_thermal_device), + GFP_KERNEL); + if (!lm95245_remote) { + pr_err("unable to allocate thermal device\n"); + return; + } + + lm95245_remote->name = "lm95245_remote"; + lm95245_remote->id = THERMAL_DEVICE_ID_NCT_EXT; + lm95245_remote->data = dev; + lm95245_remote->offset = TDIODE_OFFSET; + lm95245_remote->get_temp = lm95245_get_temp; + lm95245_remote->get_temp_low = lm95245_get_temp_low; + lm95245_remote->set_limits = lm95245_set_limits; + lm95245_remote->set_alert = lm95245_set_alert; + lm95245_remote->set_shutdown_temp = lm95245_set_shutdown_temp; + + tegra_thermal_device_register(lm95245_remote); + +#ifdef CONFIG_TEGRA_SKIN_THROTTLE + { + struct tegra_thermal_device *lm95245_local; + lm95245_local = kzalloc(sizeof(struct tegra_thermal_device), + GFP_KERNEL); + if (!lm95245_local) { + kfree(lm95245_local); + pr_err("unable to allocate thermal device\n"); + return; + } + + lm95245_local->name = "lm95245_local"; + lm95245_local->id = THERMAL_DEVICE_ID_NCT_INT; + lm95245_local->data = dev; + lm95245_local->get_temp = lm95245_get_itemp; + + tegra_thermal_device_register(lm95245_local); + } +#endif /* CONFIG_TEGRA_SKIN_THROTTLE */ + + if (request_irq(gpio_to_irq(THERMD_ALERT_N), thermd_alert_irq, + IRQF_TRIGGER_LOW, "THERMD_ALERT_N", NULL)) + pr_err("%s: unable to register THERMD_ALERT_N interrupt\n", + __func__); + + //initalize the local temp limit + if(dev) + lm95245_set_local_shared_os__critical_limit(dev, TCRIT_LOCAL); +} + +static void apalis_t30_thermd_alert_init(void) +{ + gpio_request(THERMD_ALERT_N, "THERMD_ALERT_N"); + gpio_direction_input(THERMD_ALERT_N); + + thermd_alert_workqueue = create_singlethread_workqueue("THERMD_ALERT_N" + ); + + INIT_WORK(&thermd_alert_work, thermd_alert_work_func); +} + +/* UART */ + +static struct platform_device *apalis_t30_uart_devices[] __initdata = { + &tegra_uarta_device, /* Apalis UART1 */ + &tegra_uartd_device, /* Apalis UART2 */ + &tegra_uartb_device, /* Apalis UART3 */ + &tegra_uartc_device, /* Apalis UART4 */ +}; + +static struct uart_clk_parent uart_parent_clk[] = { + [0] = {.name = "clk_m"}, + [1] = {.name = "pll_p"}, +#ifndef CONFIG_TEGRA_PLLM_RESTRICTED + [2] = {.name = "pll_m"}, +#endif +}; + +static struct tegra_uart_platform_data apalis_t30_uart_pdata; + +static void __init uart_debug_init(void) +{ + int debug_port_id; + + debug_port_id = get_tegra_uart_debug_port_id(); + if (debug_port_id < 0) { + debug_port_id = 0; + } + + switch (debug_port_id) { + case 0: + /* UARTA is the debug port. */ + pr_info("Selecting UARTA as the debug console\n"); + apalis_t30_uart_devices[0] = &debug_uarta_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uarta"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uarta_device.dev.platform_data))->mapbase; + break; + + case 1: + /* UARTB is the debug port. */ + pr_info("Selecting UARTB as the debug console\n"); + apalis_t30_uart_devices[2] = &debug_uartb_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uartb"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uartb_device.dev.platform_data))->mapbase; + break; + + case 2: + /* UARTC is the debug port. */ + pr_info("Selecting UARTC as the debug console\n"); + apalis_t30_uart_devices[3] = &debug_uartc_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uartc"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uartb_device.dev.platform_data))->mapbase; + break; + + case 3: + /* UARTD is the debug port. */ + pr_info("Selecting UARTD as the debug console\n"); + apalis_t30_uart_devices[1] = &debug_uartd_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uartd"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uartd_device.dev.platform_data))->mapbase; + break; + + default: + pr_info("The debug console id %d is invalid, Assuming UARTA", + debug_port_id); + apalis_t30_uart_devices[0] = &debug_uarta_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uarta"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uarta_device.dev.platform_data))->mapbase; + break; + } + return; +} + +static void __init apalis_t30_uart_init(void) +{ + struct clk *c; + int i; + + for (i = 0; i < ARRAY_SIZE(uart_parent_clk); ++i) { + c = tegra_get_clock_by_name(uart_parent_clk[i].name); + if (IS_ERR_OR_NULL(c)) { + pr_err("Not able to get the clock for %s\n", + uart_parent_clk[i].name); + continue; + } + uart_parent_clk[i].parent_clk = c; + uart_parent_clk[i].fixed_clk_rate = clk_get_rate(c); + } + apalis_t30_uart_pdata.parent_clk_list = uart_parent_clk; + apalis_t30_uart_pdata.parent_clk_count = ARRAY_SIZE(uart_parent_clk); + tegra_uarta_device.dev.platform_data = &apalis_t30_uart_pdata; + tegra_uartb_device.dev.platform_data = &apalis_t30_uart_pdata; + tegra_uartc_device.dev.platform_data = &apalis_t30_uart_pdata; + tegra_uartd_device.dev.platform_data = &apalis_t30_uart_pdata; + + /* Register low speed only if it is selected */ + if (!is_tegra_debug_uartport_hs()) { + uart_debug_init(); + /* Clock enable for the debug channel */ + if (!IS_ERR_OR_NULL(debug_uart_clk)) { + pr_info("The debug console clock name is %s\n", + debug_uart_clk->name); + c = tegra_get_clock_by_name("pll_p"); + if (IS_ERR_OR_NULL(c)) + pr_err("Not getting the parent clock pll_p\n"); + else + clk_set_parent(debug_uart_clk, c); + + clk_enable(debug_uart_clk); + clk_set_rate(debug_uart_clk, clk_get_rate(c)); + } else { + pr_err("Not getting the clock %s for debug console\n", + debug_uart_clk->name); + } + } + + platform_add_devices(apalis_t30_uart_devices, + ARRAY_SIZE(apalis_t30_uart_devices)); +} + +/* USB */ + +//TODO: overcurrent + +static struct tegra_usb_platform_data tegra_udc_pdata = { + .has_hostpc = true, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = true, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 8, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.dev = { + .charging_supported = false, + .remote_wakeup_supported = false, + .vbus_gpio = -1, + .vbus_pmu_irq = 0, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .has_hostpc = true, + .op_mode = TEGRA_USB_OPMODE_HOST, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = true, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 15, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.host = { + .hot_plug = true, + .power_off_on_suspend = false, + .remote_wakeup_supported = true, + .vbus_gpio = USBO1_EN, + .vbus_gpio_inverted = 0, + .vbus_reg = NULL, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = { + .has_hostpc = true, + .op_mode = TEGRA_USB_OPMODE_HOST, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = false, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 15, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.host = { + .hot_plug = true, + .power_off_on_suspend = false, + .remote_wakeup_supported = true, + .vbus_gpio = USBH_EN, + .vbus_gpio_inverted = 0, + .vbus_reg = NULL, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = { + .has_hostpc = true, + .op_mode = TEGRA_USB_OPMODE_HOST, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = false, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 8, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.host = { + .hot_plug = true, + .power_off_on_suspend = false, + .remote_wakeup_supported = true, + /* Uses same USBH_EN as EHCI2 */ + .vbus_gpio = -1, + .vbus_gpio_inverted = 0, + .vbus_reg = NULL, + }, +}; + +static struct tegra_usb_otg_data tegra_otg_pdata = { + .ehci_device = &tegra_ehci1_device, + .ehci_pdata = &tegra_ehci1_utmi_pdata, +}; + +static void apalis_t30_usb_init(void) +{ + /* OTG should be the first to be registered + EHCI instance 0: USB1_DP/N -> USBO1_DP/N */ + tegra_otg_device.dev.platform_data = &tegra_otg_pdata; + platform_device_register(&tegra_otg_device); + + /* setup the udc platform data */ + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; + platform_device_register(&tegra_udc_device); + + /* EHCI instance 1: USB2_DP/N -> USBH2_DP/N */ + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata; + platform_device_register(&tegra_ehci2_device); + + /* EHCI instance 2: USB3_DP/N -> USBH3_DP/N */ + tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata; + platform_device_register(&tegra_ehci3_device); +} + +/* W1, aka OWR, aka OneWire */ + +#ifdef CONFIG_W1_MASTER_TEGRA +struct tegra_w1_timings apalis_t30_w1_timings = { + .tsu = 1, + .trelease = 0xf, + .trdv = 0xf, + .tlow0 = 0x3c, + .tlow1 = 1, + .tslot = 0x77, + + .tpdl = 0x78, + .tpdh = 0x1e, + .trstl = 0x1df, + .trsth = 0x1df, + .rdsclk = 0x7, + .psclk = 0x50, +}; + +struct tegra_w1_platform_data apalis_t30_w1_platform_data = { + .clk_id = "tegra_w1", + .timings = &apalis_t30_w1_timings, +}; +#endif /* CONFIG_W1_MASTER_TEGRA */ + +static struct platform_device *apalis_t30_devices[] __initdata = { + &tegra_pmu_device, +#if defined(CONFIG_RTC_DRV_TEGRA) + &tegra_rtc_device, +#endif +#if defined(CONFIG_TEGRA_IOVMM_SMMU) || defined(CONFIG_TEGRA_IOMMU_SMMU) + &tegra_smmu_device, +#endif +#ifdef CONFIG_KEYBOARD_GPIO + &apalis_t30_keys_device, +#endif + &tegra_wdt0_device, + &tegra_wdt1_device, + &tegra_wdt2_device, +#if defined(CONFIG_TEGRA_AVP) + &tegra_avp_device, +#endif +#ifdef CONFIG_TEGRA_CAMERA + &tegra_camera, +#endif +#if defined(CONFIG_CRYPTO_DEV_TEGRA_SE) + &tegra_se_device, +#endif +#if defined(CONFIG_CRYPTO_DEV_TEGRA_AES) + &tegra_aes_device, +#endif + &tegra_ahub_device, + &tegra_dam_device0, + &tegra_dam_device1, + &tegra_dam_device2, + &tegra_i2s_device2, + &tegra_spdif_device, + &spdif_dit_device, + &tegra_pcm_device, + &apalis_t30_audio_sgtl5000_device, + &tegra_hda_device, + &tegra_cec_device, +#ifdef CONFIG_KEYBOARD_GPIO +// &apalis_t30_keys_device, +#endif + &tegra_led_pwm_device, + &tegra_pwfm1_device, + &tegra_pwfm2_device, + &tegra_pwfm3_device, +#ifdef CONFIG_W1_MASTER_TEGRA + &tegra_w1_device, +#endif +}; + +static void __init apalis_t30_init(void) +{ + tegra_thermal_init(&thermal_data, + throttle_list, + ARRAY_SIZE(throttle_list)); + tegra_clk_init_from_table(apalis_t30_clk_init_table); + apalis_t30_pinmux_init(); + apalis_t30_thermd_alert_init(); + apalis_t30_i2c_init(); + apalis_t30_spi_init(); + apalis_t30_usb_init(); +#ifdef CONFIG_TEGRA_EDP_LIMITS + apalis_t30_edp_init(); +#endif + apalis_t30_uart_init(); +#ifdef CONFIG_W1_MASTER_TEGRA + tegra_w1_device.dev.platform_data = &apalis_t30_w1_platform_data; +#endif + platform_add_devices(apalis_t30_devices, ARRAY_SIZE(apalis_t30_devices) + ); + tegra_ram_console_debug_init(); + tegra_io_dpd_init(); + apalis_t30_sdhci_init(); + apalis_t30_regulator_init(); + apalis_t30_suspend_init(); + apalis_t30_panel_init(); +// apalis_t30_sensors_init(); + apalis_t30_sata_init(); + apalis_t30_emc_init(); + apalis_t30_register_spidev(); + +#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE) + t30_get_tegra_vi01_device()->dev.platform_data = &tegra_camera_platform_data; +#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE) + platform_device_register(&soc_camera_max9526); +#endif +#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE) + platform_device_register(&soc_camera_adv7180); +#endif +#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */ + + tegra_release_bootloader_fb(); + apalis_t30_pci_init(); +#ifdef CONFIG_TEGRA_WDT_RECOVERY + tegra_wdt_recovery_init(); +#endif + tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1); + apalis_t30_mcp2515_can_init(); + apalis_t30_gpio_init(); +} + +static void __init apalis_t30_reserve(void) +{ +#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM) + /* Support 1920X1080 32bpp,double buffered on HDMI*/ + tegra_reserve(0, SZ_8M + SZ_1M, SZ_16M); +#else + tegra_reserve(SZ_128M, SZ_8M, SZ_8M); +#endif + tegra_ram_console_debug_reserve(SZ_1M); +} + +static const char *apalis_t30_dt_board_compat[] = { + "toradex,apalis_t30", + NULL +}; + +MACHINE_START(APALIS_T30, "Toradex Apalis T30") + .boot_params = 0x80000100, + .dt_compat = apalis_t30_dt_board_compat, + .init_early = tegra_init_early, + .init_irq = tegra_init_irq, + .init_machine = apalis_t30_init, + .map_io = tegra_map_common_io, + .reserve = apalis_t30_reserve, + .timer = &tegra_timer, +MACHINE_END diff --git a/arch/arm/mach-tegra/board-apalis_t30.h b/arch/arm/mach-tegra/board-apalis_t30.h new file mode 100644 index 000000000000..9fde9ef1d89e --- /dev/null +++ b/arch/arm/mach-tegra/board-apalis_t30.h @@ -0,0 +1,140 @@ +/* + * arch/arm/mach-tegra/board-apalis_t30.h + * + * Copyright (c) 2013 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MACH_TEGRA_BOARD_APALIS_T30_H +#define _MACH_TEGRA_BOARD_APALIS_T30_H + +#include <linux/mfd/tps6591x.h> + +#include <mach/gpio.h> +#include <mach/irqs.h> + +/* GPIO */ + +#define APALIS_GPIO1 TEGRA_GPIO_PS2 +#define APALIS_GPIO2 TEGRA_GPIO_PS3 +#define APALIS_GPIO3 TEGRA_GPIO_PS4 +#define APALIS_GPIO4 TEGRA_GPIO_PS5 +#define APALIS_GPIO5 TEGRA_GPIO_PS6 +#define APALIS_GPIO6 TEGRA_GPIO_PQ0 +#define APALIS_GPIO7 TEGRA_GPIO_PS7 +#define APALIS_GPIO8 TEGRA_GPIO_PQ1 + +#define BKL1_ON TEGRA_GPIO_PV2 +#define BKL1_PWM_EN_N TEGRA_GPIO_PA1 + +#define CAN1_INT TEGRA_GPIO_PW2 +#define CAN2_INT TEGRA_GPIO_PW3 + +#define FAN_EN APALIS_GPIO8 + +#define HDMI1_HPD TEGRA_GPIO_PN7 + +#define I2C1_SCL TEGRA_GPIO_PC4 +#define I2C1_SDA TEGRA_GPIO_PC5 + +#define I2C2_SCL TEGRA_GPIO_PV4 +#define I2C2_SDA TEGRA_GPIO_PV5 + +#define I2C3_SCL TEGRA_GPIO_PBB1 +#define I2C3_SDA TEGRA_GPIO_PBB2 + +#define LAN_SMB_ALERT_N TEGRA_GPIO_PZ5 + +#define LVDS_MODE TEGRA_GPIO_PBB0 +#define LVDS_6B_8B_N TEGRA_GPIO_PBB3 +#define LVDS_OE TEGRA_GPIO_PBB4 +#define LVDS_PDWN_N TEGRA_GPIO_PBB5 +#define LVDS_R_F_N TEGRA_GPIO_PBB6 +#define LVDS_MAP TEGRA_GPIO_PBB7 +#define LVDS_RS TEGRA_GPIO_PCC1 +#define LVDS_DDR_N TEGRA_GPIO_PCC2 + +#define MMC1_CD_N TEGRA_GPIO_PV3 + +#define PEX_PERST_N APALIS_GPIO7 + +#define PWR_I2C_SCL TEGRA_GPIO_PZ6 +#define PWR_I2C_SDA TEGRA_GPIO_PZ7 + +#define RESET_MOCI_N TEGRA_GPIO_PI4 + +#define SATA1_ACT_N TEGRA_GPIO_PDD0 + +#define SD1_CD_N TEGRA_GPIO_PCC5 + +#define THERMD_ALERT_N TEGRA_GPIO_PD2 + +#define TOUCH_PEN_INT TEGRA_GPIO_PV0 +#define TOUCH_WIPER APALIS_GPIO6 + +#define TS1 TEGRA_GPIO_PI1 +#define TS2 TEGRA_GPIO_PQ7 +#define TS3 TEGRA_GPIO_PQ5 +#define TS4 TEGRA_GPIO_PQ6 +#define TS5 TEGRA_GPIO_PS0 +#define TS6 TEGRA_GPIO_PS1 + +#define USBH_EN TEGRA_GPIO_PDD1 +#define USBH_OC_N TEGRA_GPIO_PDD2 +#define USBO1_EN TEGRA_GPIO_PT5 +#define USBO1_OC_N TEGRA_GPIO_PT6 + +#define WAKE1_MICO TEGRA_GPIO_PV1 + +/* STMPE811 IRQs */ +#define STMPE811_IRQ_BASE TEGRA_NR_IRQS +#define STMPE811_IRQ_END (STMPE811_IRQ_BASE + 22) + +#define TDIODE_OFFSET (10000) /* in millicelsius */ +#define TCRIT_LOCAL 95000 /* board temp to switch off PMIC in millicelsius*/ + +/* External peripheral act as gpio */ +/* TPS6591x GPIOs */ +#define TPS6591X_GPIO_BASE TEGRA_NR_GPIOS +#define TPS6591X_GPIO_0 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP0) +#define TPS6591X_GPIO_1 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP1) +#define TPS6591X_GPIO_2 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP2) +#define TPS6591X_GPIO_3 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP3) +#define TPS6591X_GPIO_4 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP4) +#define TPS6591X_GPIO_5 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP5) +#define TPS6591X_GPIO_6 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP6) +#define TPS6591X_GPIO_7 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP7) +#define TPS6591X_GPIO_8 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP8) +#define TPS6591X_GPIO_END (TPS6591X_GPIO_BASE + TPS6591X_GPIO_NR) + +/*****************Interrupt tables ******************/ +/* External peripheral act as interrupt controller */ +/* TPS6591x IRQs */ +#define TPS6591X_IRQ_BASE STMPE811_IRQ_END +#define TPS6591X_IRQ_END (TPS6591X_IRQ_BASE + 18) + +int apalis_t30_regulator_init(void); +int apalis_t30_suspend_init(void); +int apalis_t30_pinmux_init(void); +int apalis_t30_panel_init(void); +int apalis_t30_sensors_init(void); +int apalis_t30_gpio_switch_regulator_init(void); +int apalis_t30_pins_state_init(void); +int apalis_t30_emc_init(void); +int apalis_t30_power_off_init(void); +int apalis_t30_edp_init(void); + +#endif diff --git a/arch/arm/mach-tegra/board-aruba-sdhci.c b/arch/arm/mach-tegra/board-aruba-sdhci.c index cf29137b773f..678385f2b8bd 100644 --- a/arch/arm/mach-tegra/board-aruba-sdhci.c +++ b/arch/arm/mach-tegra/board-aruba-sdhci.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-harmony-sdhci.c + * arch/arm/mach-tegra/board-aruba-sdhci.c * * Copyright (C) 2010 Google, Inc. * diff --git a/arch/arm/mach-tegra/board-cardhu-sdhci.c b/arch/arm/mach-tegra/board-cardhu-sdhci.c index df7177fb34a7..6b8948b874ff 100644 --- a/arch/arm/mach-tegra/board-cardhu-sdhci.c +++ b/arch/arm/mach-tegra/board-cardhu-sdhci.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-harmony-sdhci.c + * arch/arm/mach-tegra/board-cardhu-sdhci.c * * Copyright (C) 2010 Google, Inc. * Copyright (C) 2011-2012 NVIDIA Corporation. diff --git a/arch/arm/mach-tegra/board-colibri_t20-memory.c b/arch/arm/mach-tegra/board-colibri_t20-memory.c new file mode 100644 index 000000000000..65b24bfa6544 --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t20-memory.c @@ -0,0 +1,464 @@ +/* + * arch/arm/mach-tegra/board-colibri_t20-memory.c + * + * Copyright (C) 2012 Toradex, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/memblock.h> + +#include "board-colibri_t20.h" +#include "board.h" +#include "tegra2_emc.h" + +/* Optimised timings for Colibri T20 256 MB */ +static const struct tegra_emc_table colibri_t20_emc_tables_nanya_333Mhz[] = { + { + .rate = 83250, /* SDRAM frequency */ + .regs = { + 0x00000005, /* RC */ + 0x00000011, /* RFC */ + 0x00000004, /* RAS */ + 0x00000002, /* RP */ + 0x00000004, /* R2W */ + 0x00000004, /* W2R */ + 0x00000001, /* R2P */ + 0x0000000a, /* W2P */ + 0x00000002, /* RD_RCD */ + 0x00000002, /* WR_RCD */ + 0x00000001, /* RRD */ + 0x00000001, /* REXT */ + 0x00000003, /* WDV */ + 0x00000004, /* QUSE */ + 0x00000003, /* QRST */ + 0x00000009, /* QSAFE */ + 0x0000000c, /* RDV */ + 0x0000025f, /* REFRESH */ + 0x00000000, /* BURST_REFRESH_NUM */ + 0x00000003, /* PDEX2WR */ + 0x00000003, /* PDEX2RD */ + 0x00000002, /* PCHG2PDEN */ + 0x00000002, /* ACT2PDEN */ + 0x00000001, /* AR2PDEN */ + 0x00000008, /* RW2PDEN */ + 0x000000c8, /* TXSR */ + 0x00000003, /* TCKE */ + 0x00000005, /* TFAW */ + 0x00000003, /* TRPAB */ + 0x00000006, /* TCLKSTABLE */ + 0x00000002, /* TCLKSTOP */ + 0x00000000, /* TREFBW */ + 0x00000000, /* QUSE_EXTRA */ + 0x00000002, /* FBIO_CFG6 */ + 0x00000000, /* ODT_WRITE */ + 0x00000000, /* ODT_READ */ + 0x00000083, /* FBIO_CFG5 */ + 0x00520006, /* CFG_DIG_DLL */ + 0x00000010, /* DLL_XFORM_DQS */ + 0x00000008, /* DLL_XFORM_QUSE */ + 0x00000000, /* ZCAL_REF_CNT */ + 0x00000000, /* ZCAL_WAIT_CNT */ + 0x00000000, /* AUTO_CAL_INTERVAL */ + 0x00000000, /* CFG_CLKTRIM_0 */ + 0x00000000, /* CFG_CLKTRIM_1 */ + 0x00000000, /* CFG_CLKTRIM_2 */ + } + }, + { + .rate = 125000, /* SDRAM frequency */ + .regs = { + 0x00000008, /* RC */ + 0x00000010, /* RFC */ + 0x00000006, /* RAS */ + 0x00000002, /* RP */ + 0x00000004, /* R2W */ + 0x00000004, /* W2R */ + 0x00000001, /* R2P */ + 0x0000000a, /* W2P */ + 0x00000002, /* RD_RCD */ + 0x00000002, /* WR_RCD */ + 0x00000002, /* RRD */ + 0x00000001, /* REXT */ + 0x00000003, /* WDV */ + 0x00000004, /* QUSE */ + 0x00000003, /* QRST */ + 0x00000009, /* QSAFE */ + 0x0000000c, /* RDV */ + 0x0000039f, /* REFRESH */ + 0x00000000, /* BURST_REFRESH_NUM */ + 0x00000003, /* PDEX2WR */ + 0x00000003, /* PDEX2RD */ + 0x00000002, /* PCHG2PDEN */ + 0x00000002, /* ACT2PDEN */ + 0x00000001, /* AR2PDEN */ + 0x00000008, /* RW2PDEN */ + 0x000000c8, /* TXSR */ + 0x00000003, /* TCKE */ + 0x00000007, /* TFAW */ + 0x00000003, /* TRPAB */ + 0x00000006, /* TCLKSTABLE */ + 0x00000002, /* TCLKSTOP */ + 0x00000000, /* TREFBW */ + 0x00000000, /* QUSE_EXTRA */ + 0x00000002, /* FBIO_CFG6 */ + 0x00000000, /* ODT_WRITE */ + 0x00000000, /* ODT_READ */ + 0x00000083, /* FBIO_CFG5 */ + 0x00510006, /* CFG_DIG_DLL */ + 0x00000010, /* DLL_XFORM_DQS */ + 0x00000008, /* DLL_XFORM_QUSE */ + 0x00000000, /* ZCAL_REF_CNT */ + 0x00000000, /* ZCAL_WAIT_CNT */ + 0x00000000, /* AUTO_CAL_INTERVAL */ + 0x00000000, /* CFG_CLKTRIM_0 */ + 0x00000000, /* CFG_CLKTRIM_1 */ + 0x00000000, /* CFG_CLKTRIM_2 */ + } + }, + { + .rate = 166500, /* SDRAM frequency */ + .regs = { + 0x0000000a, /* RC */ + 0x00000016, /* RFC */ + 0x00000008, /* RAS */ + 0x00000003, /* RP */ + 0x00000004, /* R2W */ + 0x00000004, /* W2R */ + 0x00000002, /* R2P */ + 0x0000000a, /* W2P */ + 0x00000003, /* RD_RCD */ + 0x00000003, /* WR_RCD */ + 0x00000002, /* RRD */ + 0x00000001, /* REXT */ + 0x00000003, /* WDV */ + 0x00000004, /* QUSE */ + 0x00000003, /* QRST */ + 0x00000009, /* QSAFE */ + 0x0000000c, /* RDV */ + 0x000004df, /* REFRESH */ + 0x00000000, /* BURST_REFRESH_NUM */ + 0x00000003, /* PDEX2WR */ + 0x00000003, /* PDEX2RD */ + 0x00000003, /* PCHG2PDEN */ + 0x00000003, /* ACT2PDEN */ + 0x00000001, /* AR2PDEN */ + 0x00000009, /* RW2PDEN */ + 0x000000c8, /* TXSR */ + 0x00000003, /* TCKE */ + 0x00000009, /* TFAW */ + 0x00000004, /* TRPAB */ + 0x00000006, /* TCLKSTABLE */ + 0x00000002, /* TCLKSTOP */ + 0x00000000, /* TREFBW */ + 0x00000000, /* QUSE_EXTRA */ + 0x00000002, /* FBIO_CFG6 */ + 0x00000000, /* ODT_WRITE */ + 0x00000000, /* ODT_READ */ + 0x00000083, /* FBIO_CFG5 */ + 0x004f0006, /* CFG_DIG_DLL */ + 0x00000010, /* DLL_XFORM_DQS */ + 0x00000008, /* DLL_XFORM_QUSE */ + 0x00000000, /* ZCAL_REF_CNT */ + 0x00000000, /* ZCAL_WAIT_CNT */ + 0x00000000, /* AUTO_CAL_INTERVAL */ + 0x00000000, /* CFG_CLKTRIM_0 */ + 0x00000000, /* CFG_CLKTRIM_1 */ + 0x00000000, /* CFG_CLKTRIM_2 */ + } + }, + { + .rate = 333000, /* SDRAM frequency */ + .regs = { + 0x00000014, /* RC */ + 0x0000002b, /* RFC */ + 0x0000000f, /* RAS */ + 0x00000005, /* RP */ + 0x00000004, /* R2W */ + 0x00000005, /* W2R */ + 0x00000003, /* R2P */ + 0x0000000a, /* W2P */ + 0x00000005, /* RD_RCD */ + 0x00000005, /* WR_RCD */ + 0x00000004, /* RRD */ + 0x00000001, /* REXT */ + 0x00000003, /* WDV */ + 0x00000004, /* QUSE */ + 0x00000003, /* QRST */ + 0x00000009, /* QSAFE */ + 0x0000000c, /* RDV */ + 0x000009ff, /* REFRESH */ + 0x00000000, /* BURST_REFRESH_NUM */ + 0x00000003, /* PDEX2WR */ + 0x00000003, /* PDEX2RD */ + 0x00000005, /* PCHG2PDEN */ + 0x00000005, /* ACT2PDEN */ + 0x00000001, /* AR2PDEN */ + 0x0000000e, /* RW2PDEN */ + 0x000000c8, /* TXSR */ + 0x00000003, /* TCKE */ + 0x00000011, /* TFAW */ + 0x00000006, /* TRPAB */ + 0x00000006, /* TCLKSTABLE */ + 0x00000002, /* TCLKSTOP */ + 0x00000000, /* TREFBW */ + 0x00000000, /* QUSE_EXTRA */ + 0x00000002, /* FBIO_CFG6 */ + 0x00000000, /* ODT_WRITE */ + 0x00000000, /* ODT_READ */ + 0x00000083, /* FBIO_CFG5 */ + 0x00380006, /* CFG_DIG_DLL */ + 0x00000010, /* DLL_XFORM_DQS */ + 0x00000008, /* DLL_XFORM_QUSE */ + 0x00000000, /* ZCAL_REF_CNT */ + 0x00000000, /* ZCAL_WAIT_CNT */ + 0x00000000, /* AUTO_CAL_INTERVAL */ + 0x00000000, /* CFG_CLKTRIM_0 */ + 0x00000000, /* CFG_CLKTRIM_1 */ + 0x00000000, /* CFG_CLKTRIM_2 */ + } + }, +}; + +/* Standard timings for Colibri T20 512 MB */ +static const struct tegra_emc_table colibri_t20_emc_tables_memphis_333Mhz[] = { + { + .rate = 83250, /* SDRAM frequency */ + .regs = { + 0x00000005, /* RC */ + 0x00000011, /* RFC */ + 0x00000004, /* RAS */ + 0x00000002, /* RP */ + 0x00000004, /* R2W */ + 0x00000004, /* W2R */ + 0x00000001, /* R2P */ + 0x0000000a, /* W2P */ + 0x00000002, /* RD_RCD */ + 0x00000002, /* WR_RCD */ + 0x00000001, /* RRD */ + 0x00000001, /* REXT */ + 0x00000003, /* WDV */ + 0x00000004, /* QUSE */ + 0x00000003, /* QRST */ + 0x00000009, /* QSAFE */ + 0x0000000c, /* RDV */ + 0x0000025f, /* REFRESH */ + 0x00000000, /* BURST_REFRESH_NUM */ + 0x00000003, /* PDEX2WR */ + 0x00000003, /* PDEX2RD */ + 0x00000002, /* PCHG2PDEN */ + 0x00000002, /* ACT2PDEN */ + 0x00000001, /* AR2PDEN */ + 0x00000008, /* RW2PDEN */ + 0x000000c8, /* TXSR */ + 0x00000003, /* TCKE */ + 0x00000005, /* TFAW */ + 0x00000003, /* TRPAB */ + 0x0000000c, /* TCLKSTABLE */ + 0x00000002, /* TCLKSTOP */ + 0x00000000, /* TREFBW */ + 0x00000000, /* QUSE_EXTRA */ + 0x00000002, /* FBIO_CFG6 */ + 0x00000000, /* ODT_WRITE */ + 0x00000000, /* ODT_READ */ + 0x00000083, /* FBIO_CFG5 */ + 0x00520006, /* CFG_DIG_DLL */ + 0x00000010, /* DLL_XFORM_DQS */ + 0x00000008, /* DLL_XFORM_QUSE */ + 0x00000000, /* ZCAL_REF_CNT */ + 0x00000000, /* ZCAL_WAIT_CNT */ + 0x00000000, /* AUTO_CAL_INTERVAL */ + 0x00000000, /* CFG_CLKTRIM_0 */ + 0x00000000, /* CFG_CLKTRIM_1 */ + 0x00000000, /* CFG_CLKTRIM_2 */ + } + }, + { + .rate = 125000, /* SDRAM frequency */ + .regs = { + 0x00000008, /* RC */ + 0x00000019, /* RFC */ + 0x00000006, /* RAS */ + 0x00000002, /* RP */ + 0x00000004, /* R2W */ + 0x00000004, /* W2R */ + 0x00000001, /* R2P */ + 0x0000000a, /* W2P */ + 0x00000002, /* RD_RCD */ + 0x00000002, /* WR_RCD */ + 0x00000002, /* RRD */ + 0x00000001, /* REXT */ + 0x00000003, /* WDV */ + 0x00000004, /* QUSE */ + 0x00000003, /* QRST */ + 0x00000009, /* QSAFE */ + 0x0000000c, /* RDV */ + 0x0000039f, /* REFRESH */ + 0x00000000, /* BURST_REFRESH_NUM */ + 0x00000003, /* PDEX2WR */ + 0x00000003, /* PDEX2RD */ + 0x00000002, /* PCHG2PDEN */ + 0x00000002, /* ACT2PDEN */ + 0x00000001, /* AR2PDEN */ + 0x00000008, /* RW2PDEN */ + 0x000000c8, /* TXSR */ + 0x00000003, /* TCKE */ + 0x00000007, /* TFAW */ + 0x00000003, /* TRPAB */ + 0x0000000c, /* TCLKSTABLE */ + 0x00000002, /* TCLKSTOP */ + 0x00000000, /* TREFBW */ + 0x00000000, /* QUSE_EXTRA */ + 0x00000002, /* FBIO_CFG6 */ + 0x00000000, /* ODT_WRITE */ + 0x00000000, /* ODT_READ */ + 0x00000083, /* FBIO_CFG5 */ + 0x00510006, /* CFG_DIG_DLL */ + 0x00000010, /* DLL_XFORM_DQS */ + 0x00000008, /* DLL_XFORM_QUSE */ + 0x00000000, /* ZCAL_REF_CNT */ + 0x00000000, /* ZCAL_WAIT_CNT */ + 0x00000000, /* AUTO_CAL_INTERVAL */ + 0x00000000, /* CFG_CLKTRIM_0 */ + 0x00000000, /* CFG_CLKTRIM_1 */ + 0x00000000, /* CFG_CLKTRIM_2 */ + } + }, + { + .rate = 166500, /* SDRAM frequency */ + .regs = { + 0x0000000a, /* RC */ + 0x00000021, /* RFC */ + 0x00000008, /* RAS */ + 0x00000003, /* RP */ + 0x00000004, /* R2W */ + 0x00000004, /* W2R */ + 0x00000002, /* R2P */ + 0x0000000a, /* W2P */ + 0x00000003, /* RD_RCD */ + 0x00000003, /* WR_RCD */ + 0x00000002, /* RRD */ + 0x00000001, /* REXT */ + 0x00000003, /* WDV */ + 0x00000004, /* QUSE */ + 0x00000003, /* QRST */ + 0x00000009, /* QSAFE */ + 0x0000000c, /* RDV */ + 0x000004df, /* REFRESH */ + 0x00000000, /* BURST_REFRESH_NUM */ + 0x00000003, /* PDEX2WR */ + 0x00000003, /* PDEX2RD */ + 0x00000003, /* PCHG2PDEN */ + 0x00000003, /* ACT2PDEN */ + 0x00000001, /* AR2PDEN */ + 0x00000009, /* RW2PDEN */ + 0x000000c8, /* TXSR */ + 0x00000003, /* TCKE */ + 0x00000009, /* TFAW */ + 0x00000004, /* TRPAB */ + 0x0000000c, /* TCLKSTABLE */ + 0x00000002, /* TCLKSTOP */ + 0x00000000, /* TREFBW */ + 0x00000000, /* QUSE_EXTRA */ + 0x00000002, /* FBIO_CFG6 */ + 0x00000000, /* ODT_WRITE */ + 0x00000000, /* ODT_READ */ + 0x00000083, /* FBIO_CFG5 */ + 0x004f0006, /* CFG_DIG_DLL */ + 0x00000010, /* DLL_XFORM_DQS */ + 0x00000008, /* DLL_XFORM_QUSE */ + 0x00000000, /* ZCAL_REF_CNT */ + 0x00000000, /* ZCAL_WAIT_CNT */ + 0x00000000, /* AUTO_CAL_INTERVAL */ + 0x00000000, /* CFG_CLKTRIM_0 */ + 0x00000000, /* CFG_CLKTRIM_1 */ + 0x00000000, /* CFG_CLKTRIM_2 */ + } + }, + { + .rate = 333000, /* SDRAM frequency */ + .regs = { + 0x00000014, /* RC */ + 0x00000041, /* RFC */ + 0x0000000f, /* RAS */ + 0x00000005, /* RP */ + 0x00000004, /* R2W */ + 0x00000005, /* W2R */ + 0x00000003, /* R2P */ + 0x0000000a, /* W2P */ + 0x00000005, /* RD_RCD */ + 0x00000005, /* WR_RCD */ + 0x00000004, /* RRD */ + 0x00000001, /* REXT */ + 0x00000003, /* WDV */ + 0x00000004, /* QUSE */ + 0x00000003, /* QRST */ + 0x00000009, /* QSAFE */ + 0x0000000c, /* RDV */ + 0x000009ff, /* REFRESH */ + 0x00000000, /* BURST_REFRESH_NUM */ + 0x00000003, /* PDEX2WR */ + 0x00000003, /* PDEX2RD */ + 0x00000005, /* PCHG2PDEN */ + 0x00000005, /* ACT2PDEN */ + 0x00000001, /* AR2PDEN */ + 0x0000000e, /* RW2PDEN */ + 0x000000c8, /* TXSR */ + 0x00000003, /* TCKE */ + 0x00000011, /* TFAW */ + 0x00000006, /* TRPAB */ + 0x0000000c, /* TCLKSTABLE */ + 0x00000002, /* TCLKSTOP */ + 0x00000000, /* TREFBW */ + 0x00000000, /* QUSE_EXTRA */ + 0x00000002, /* FBIO_CFG6 */ + 0x00000000, /* ODT_WRITE */ + 0x00000000, /* ODT_READ */ + 0x00000083, /* FBIO_CFG5 */ + 0x00380006, /* CFG_DIG_DLL */ + 0x00000010, /* DLL_XFORM_DQS */ + 0x00000008, /* DLL_XFORM_QUSE */ + 0x00000000, /* ZCAL_REF_CNT */ + 0x00000000, /* ZCAL_WAIT_CNT */ + 0x00000000, /* AUTO_CAL_INTERVAL */ + 0x00000000, /* CFG_CLKTRIM_0 */ + 0x00000000, /* CFG_CLKTRIM_1 */ + 0x00000000, /* CFG_CLKTRIM_2 */ + } + }, +}; + +static const struct tegra_emc_chip colibri_t20_emc_chips[] = { + { + .description = "Nanya NT5TU64M16GG 333MHz", + .table = colibri_t20_emc_tables_nanya_333Mhz, + .table_size = ARRAY_SIZE(colibri_t20_emc_tables_nanya_333Mhz) + }, + { + .description = "MEMPHIS MEM2G16D2DABG 333MHz", + .table = colibri_t20_emc_tables_memphis_333Mhz, + .table_size = ARRAY_SIZE(colibri_t20_emc_tables_memphis_333Mhz) + }, +}; + +int colibri_t20_emc_init(void) +{ + /* Assume less than 256 MB of kernel memory (e.g. physical memory minus + carveout and framebuffers) means we are running on a 256 MB module */ + if (memblock_end_of_DRAM() < 256 * 1024 * 1024) + tegra_init_emc(&colibri_t20_emc_chips[0], 1); + else + tegra_init_emc(&colibri_t20_emc_chips[1], 1); + + return 0; +} diff --git a/arch/arm/mach-tegra/board-colibri_t20-panel.c b/arch/arm/mach-tegra/board-colibri_t20-panel.c new file mode 100644 index 000000000000..4c11b6c7f6e1 --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t20-panel.c @@ -0,0 +1,473 @@ +/* + * arch/arm/mach-tegra/board-colibri_t20-panel.c + * + * Copyright (c) 2012, Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <asm/mach-types.h> + +#include <linux/delay.h> +#include <linux/earlysuspend.h> +#include <linux/gpio.h> +#include <linux/nvhost.h> +#include <linux/nvmap.h> +#include <linux/platform_device.h> +#include <linux/pwm_backlight.h> +#include <linux/regulator/consumer.h> +#include <linux/resource.h> + +#include <mach/dc.h> +#include <mach/fb.h> +#include <mach/iomap.h> +#include <mach/irqs.h> + +#include "board.h" +#include "board-colibri_t20.h" +#include "devices.h" +#include "gpio-names.h" +#include "tegra2_host1x_devices.h" + +#ifndef COLIBRI_T20_VI +#define colibri_t20_bl_enb TEGRA_GPIO_PT4 /* BL_ON */ +#endif +#define colibri_t20_hdmi_hpd TEGRA_GPIO_PN7 /* HOTPLUG_DETECT */ +#ifdef IRIS +#define iris_dac_psave TEGRA_GPIO_PA0 /* DAC_PSAVE# */ +#endif + +#ifdef CONFIG_TEGRA_DC +static struct regulator *colibri_t20_hdmi_reg = NULL; +static struct regulator *colibri_t20_hdmi_pll = NULL; +#endif + +#ifndef COLIBRI_T20_VI +static int colibri_t20_backlight_init(struct device *dev) { + int ret; + + ret = gpio_request(colibri_t20_bl_enb, "BL_ON"); + if (ret < 0) + return ret; + + ret = gpio_direction_output(colibri_t20_bl_enb, 1); + if (ret < 0) + gpio_free(colibri_t20_bl_enb); + + return ret; +}; + +static void colibri_t20_backlight_exit(struct device *dev) { + gpio_set_value(colibri_t20_bl_enb, 0); + gpio_free(colibri_t20_bl_enb); +} + +static int colibri_t20_backlight_notify(struct device *dev, int brightness) +{ + struct platform_pwm_backlight_data *pdata = dev->platform_data; + + gpio_set_value(colibri_t20_bl_enb, !!brightness); + + /* Unified TFT interface displays (e.g. EDT ET070080DH6) LEDCTRL pin + with inverted behaviour (e.g. 0V brightest vs. 3.3V darkest) + Note: brightness polarity display model specific */ + if (brightness) return pdata->max_brightness - brightness; + else return brightness; +} + +static int colibri_t20_disp1_check_fb(struct device *dev, struct fb_info *info); + +static struct platform_pwm_backlight_data colibri_t20_backlight_data = { +#ifndef MECS_TELLURIUM + .pwm_id = 0, /* PWM<A> (PMFM_PWM0) */ +#else + .pwm_id = 2, /* PWM<C> (PMFM_PWM2) */ +#endif + .max_brightness = 255, + .dft_brightness = 127, + .pwm_period_ns = 1000000, /* 1 kHz */ + .init = colibri_t20_backlight_init, + .exit = colibri_t20_backlight_exit, + .notify = colibri_t20_backlight_notify, + /* Only toggle backlight on fb blank notifications for disp1 */ + .check_fb = colibri_t20_disp1_check_fb, +}; + +static struct platform_device colibri_t20_backlight_device = { + .name = "pwm-backlight", + .id = -1, + .dev = { + .platform_data = &colibri_t20_backlight_data, + }, +}; +#endif /* !COLIBRI_T20_VI */ + +#ifdef CONFIG_TEGRA_DC +static int colibri_t20_panel_enable(void) +{ +#ifdef IRIS + gpio_set_value(iris_dac_psave, 1); +#endif + return 0; +} + +static int colibri_t20_panel_disable(void) +{ +#ifdef IRIS + gpio_set_value(iris_dac_psave, 0); +#endif + return 0; +} + +static int colibri_t20_hdmi_enable(void) +{ + if (!colibri_t20_hdmi_reg) { + colibri_t20_hdmi_reg = regulator_get(NULL, "avdd_hdmi"); /* LD07 */ + if (IS_ERR_OR_NULL(colibri_t20_hdmi_reg)) { + pr_err("hdmi: couldn't get regulator avdd_hdmi\n"); + colibri_t20_hdmi_reg = NULL; + return PTR_ERR(colibri_t20_hdmi_reg); + } + } + regulator_enable(colibri_t20_hdmi_reg); + + if (!colibri_t20_hdmi_pll) { + colibri_t20_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll"); /* LD08 */ + if (IS_ERR_OR_NULL(colibri_t20_hdmi_pll)) { + pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n"); + colibri_t20_hdmi_pll = NULL; + regulator_disable(colibri_t20_hdmi_reg); + colibri_t20_hdmi_reg = NULL; + return PTR_ERR(colibri_t20_hdmi_pll); + } + } + regulator_enable(colibri_t20_hdmi_pll); + return 0; +} + +static int colibri_t20_hdmi_disable(void) +{ + regulator_disable(colibri_t20_hdmi_reg); + regulator_disable(colibri_t20_hdmi_pll); + return 0; +} + +static struct resource colibri_t20_disp1_resources[] = { + { + .name = "irq", + .start = INT_DISPLAY_GENERAL, + .end = INT_DISPLAY_GENERAL, + .flags = IORESOURCE_IRQ, + }, + { + .name = "regs", + .start = TEGRA_DISPLAY_BASE, + .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1, + .flags = IORESOURCE_MEM, + }, + { + .name = "fbmem", + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource colibri_t20_disp2_resources[] = { + { + .name = "irq", + .start = INT_DISPLAY_B_GENERAL, + .end = INT_DISPLAY_B_GENERAL, + .flags = IORESOURCE_IRQ, + }, + { + .name = "regs", + .start = TEGRA_DISPLAY2_BASE, + .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "fbmem", + .flags = IORESOURCE_MEM, + }, + { + .name = "hdmi_regs", + .start = TEGRA_HDMI_BASE, + .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct tegra_fb_data colibri_t20_fb_data = { + .win = 0, + .flags = TEGRA_FB_FLIP_ON_PROBE, +}; + +static struct tegra_fb_data colibri_t20_hdmi_fb_data = { + .win = 0, + .flags = TEGRA_FB_FLIP_ON_PROBE, +}; + +static struct tegra_dc_out_pin colibri_t20_dc_out_pins[] = { + { + .name = TEGRA_DC_OUT_PIN_H_SYNC, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, + { + .name = TEGRA_DC_OUT_PIN_V_SYNC, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, + { + .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, +}; + +static struct tegra_dc_out colibri_t20_disp1_out = { + .type = TEGRA_DC_OUT_RGB, + .parent_clk = "pll_p", + .parent_clk_backup = "pll_d", + + .max_pixclock = KHZ2PICOS(162000), + + .align = TEGRA_DC_ALIGN_MSB, + .order = TEGRA_DC_ORDER_RED_BLUE, + .depth = 18, + .dither = TEGRA_DC_ORDERED_DITHER, + + /* Use 32-bit depth for android builds */ +#ifdef CONFIG_ANDROID + .default_mode = "640x480-32@60", +#else /* CONFIG_ANDROID */ + .default_mode = "640x480-16@60", +#endif /* CONFIG_ANDROID */ + + .out_pins = colibri_t20_dc_out_pins, + .n_out_pins = ARRAY_SIZE(colibri_t20_dc_out_pins), + + .enable = colibri_t20_panel_enable, + .disable = colibri_t20_panel_disable, +}; + +static struct tegra_dc_out colibri_t20_disp2_out = { + .type = TEGRA_DC_OUT_HDMI, + .flags = TEGRA_DC_OUT_HOTPLUG_HIGH, + + .dcc_bus = 1, + .hotplug_gpio = colibri_t20_hdmi_hpd, + + .max_pixclock = KHZ2PICOS(148500), + + /* Use 32-bit depth for android builds */ +#ifdef CONFIG_ANDROID + .default_mode = "640x480-32@60", +#else /* CONFIG_ANDROID */ + .default_mode = "640x480-16@60", +#endif /* CONFIG_ANDROID */ + + .align = TEGRA_DC_ALIGN_MSB, + .order = TEGRA_DC_ORDER_RED_BLUE, + + .enable = colibri_t20_hdmi_enable, + .disable = colibri_t20_hdmi_disable, + +// .dither = TEGRA_DC_ORDERED_DITHER, +}; + +static struct tegra_dc_platform_data colibri_t20_disp1_pdata = { + .flags = TEGRA_DC_FLAG_ENABLED, + .default_out = &colibri_t20_disp1_out, + .fb = &colibri_t20_fb_data, +}; + +static struct tegra_dc_platform_data colibri_t20_disp2_pdata = { + .flags = TEGRA_DC_FLAG_ENABLED, + .default_out = &colibri_t20_disp2_out, + .fb = &colibri_t20_hdmi_fb_data, +}; + +static struct nvhost_device colibri_t20_disp1_device = { + .name = "tegradc", + .id = 0, + .resource = colibri_t20_disp1_resources, + .num_resources = ARRAY_SIZE(colibri_t20_disp1_resources), + .dev = { + .platform_data = &colibri_t20_disp1_pdata, + }, +}; + +#ifndef COLIBRI_T20_VI +static int colibri_t20_disp1_check_fb(struct device *dev, struct fb_info *info) +{ + return info->device == &colibri_t20_disp1_device.dev; +} +#endif /* !COLIBRI_T20_VI */ + +static struct nvhost_device colibri_t20_disp2_device = { + .name = "tegradc", + .id = 1, + .resource = colibri_t20_disp2_resources, + .num_resources = ARRAY_SIZE(colibri_t20_disp2_resources), + .dev = { + .platform_data = &colibri_t20_disp2_pdata, + }, +}; +#else /* CONFIG_TEGRA_DC */ +static int colibri_t20_disp1_check_fb(struct device *dev, struct fb_info *info) +{ + return 0; +} +#endif /* CONFIG_TEGRA_DC */ + +#if defined(CONFIG_TEGRA_NVMAP) +static struct nvmap_platform_carveout colibri_t20_carveouts[] = { + [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT, + [1] = { + .name = "generic-0", + .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC, + .buddy_size = SZ_32K, + }, +}; + +static struct nvmap_platform_data colibri_t20_nvmap_data = { + .carveouts = colibri_t20_carveouts, + .nr_carveouts = ARRAY_SIZE(colibri_t20_carveouts), +}; + +static struct platform_device colibri_t20_nvmap_device = { + .name = "tegra-nvmap", + .id = -1, + .dev = { + .platform_data = &colibri_t20_nvmap_data, + }, +}; +#endif /* CONFIG_TEGRA_NVMAP */ + +static struct platform_device *colibri_t20_gfx_devices[] __initdata = { +#if defined(CONFIG_TEGRA_NVMAP) + &colibri_t20_nvmap_device, +#endif +#ifndef COLIBRI_T20_VI +#ifndef MECS_TELLURIUM + &tegra_pwfm0_device, +#else + &tegra_pwfm2_device, +#endif + &colibri_t20_backlight_device, +#endif /* !COLIBRI_T20_VI */ +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +/* put early_suspend/late_resume handlers here for the display in order + * to keep the code out of the display driver, keeping it closer to upstream + */ +struct early_suspend colibri_t20_panel_early_suspender; + +static void colibri_t20_panel_early_suspend(struct early_suspend *h) +{ + /* power down LCD, add use a black screen for HDMI */ + if (num_registered_fb > 0) + fb_blank(registered_fb[0], FB_BLANK_POWERDOWN); + if (num_registered_fb > 1) + fb_blank(registered_fb[1], FB_BLANK_NORMAL); +#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND + cpufreq_store_default_gov(); + cpufreq_change_gov(cpufreq_conservative_gov); +#endif +} + +static void colibri_t20_panel_late_resume(struct early_suspend *h) +{ + unsigned i; +#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND + cpufreq_restore_default_gov(); +#endif + for (i = 0; i < num_registered_fb; i++) + fb_blank(registered_fb[i], FB_BLANK_UNBLANK); +} +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +int __init colibri_t20_panel_init(void) +{ + int err; + struct resource __maybe_unused *res; + void __iomem *to_io; + +#ifdef IRIS + gpio_request(iris_dac_psave, "Iris DAC_PSAVE#"); + gpio_direction_output(iris_dac_psave, 1); +#endif /* IRIS */ + + /* enable hdmi hotplug gpio for hotplug detection */ + gpio_request(colibri_t20_hdmi_hpd, "hdmi_hpd"); + gpio_direction_input(colibri_t20_hdmi_hpd); + +#ifdef CONFIG_HAS_EARLYSUSPEND + colibri_t20_panel_early_suspender.suspend = colibri_t20_panel_early_suspend; + colibri_t20_panel_early_suspender.resume = colibri_t20_panel_late_resume; + colibri_t20_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + register_early_suspend(&colibri_t20_panel_early_suspender); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +#if defined(CONFIG_TEGRA_NVMAP) + colibri_t20_carveouts[1].base = tegra_carveout_start; + colibri_t20_carveouts[1].size = tegra_carveout_size; +#endif /* CONFIG_TEGRA_NVMAP */ + +#ifdef CONFIG_TEGRA_GRHOST + err = tegra2_register_host1x_devices(); + if (err) + return err; +#endif /* CONFIG_TEGRA_NVMAP */ + + err = platform_add_devices(colibri_t20_gfx_devices, + ARRAY_SIZE(colibri_t20_gfx_devices)); + +#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) + res = nvhost_get_resource_byname(&colibri_t20_disp1_device, + IORESOURCE_MEM, "fbmem"); + res->start = tegra_fb_start; + res->end = tegra_fb_start + tegra_fb_size - 1; + + res = nvhost_get_resource_byname(&colibri_t20_disp2_device, + IORESOURCE_MEM, "fbmem"); + res->start = tegra_fb2_start; + res->end = tegra_fb2_start + tegra_fb2_size - 1; +#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */ + + /* Make sure LVDS framebuffer is cleared. */ + to_io = ioremap(tegra_fb_start, tegra_fb_size); + if (to_io) { + memset(to_io, 0, tegra_fb_size); + iounmap(to_io); + } else pr_err("%s: Failed to map LVDS framebuffer\n", __func__); + + /* Make sure HDMI framebuffer is cleared. + Note: this seems to fix a tegradc.1 initialisation race in case of + framebuffer console as well. */ + to_io = ioremap(tegra_fb2_start, tegra_fb2_size); + if (to_io) { + memset(to_io, 0, tegra_fb2_size); + iounmap(to_io); + } else pr_err("%s: Failed to map HDMI framebuffer\n", __func__); + +#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) + if (!err) + err = nvhost_device_register(&colibri_t20_disp1_device); + + if (!err) + err = nvhost_device_register(&colibri_t20_disp2_device); +#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */ + + return err; +} diff --git a/arch/arm/mach-tegra/board-colibri_t20-pinmux.c b/arch/arm/mach-tegra/board-colibri_t20-pinmux.c new file mode 100644 index 000000000000..85a28213dbe2 --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t20-pinmux.c @@ -0,0 +1,386 @@ +/* + * arch/arm/mach-tegra/board-colibri_t20-pinmux.c + * + * Copyright (C) 2011 Toradex, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/kernel.h> + +#include <mach/pinmux.h> + +#include "board-colibri_t20.h" +#include "gpio-names.h" + +#define DEFAULT_DRIVE(_name) \ + { \ + .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \ + .hsm = TEGRA_HSM_DISABLE, \ + .schmitt = TEGRA_SCHMITT_ENABLE, \ + .drive = TEGRA_DRIVE_DIV_1, \ + .pull_down = TEGRA_PULL_31, \ + .pull_up = TEGRA_PULL_31, \ + .slew_rising = TEGRA_SLEW_SLOWEST, \ + .slew_falling = TEGRA_SLEW_SLOWEST, \ + } + +#define SET_DRIVE(_name, _hsm, _schmitt, _drive, _pulldn_drive, _pullup_drive, _pulldn_slew, _pullup_slew) \ + { \ + .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \ + .hsm = TEGRA_HSM_##_hsm, \ + .schmitt = TEGRA_SCHMITT_##_schmitt, \ + .drive = TEGRA_DRIVE_##_drive, \ + .pull_down = TEGRA_PULL_##_pulldn_drive, \ + .pull_up = TEGRA_PULL_##_pullup_drive, \ + .slew_rising = TEGRA_SLEW_##_pulldn_slew, \ + .slew_falling = TEGRA_SLEW_##_pullup_slew, \ + } + +static __initdata struct tegra_drive_pingroup_config colibri_t20_drive_pinmux[] = { + DEFAULT_DRIVE(SDIO1), + DEFAULT_DRIVE(VI1), + + SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + SET_DRIVE(AT1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + SET_DRIVE(VI2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), +}; + +static __initdata int colibri_t20_gpio_input_pinmux[] = { + /* SODIMM pin 152 tri-stating GMI_CLK as OWR can not be tri-stated */ +//currently reserved during board platform GPIO handling +// TEGRA_GPIO_PK1, /* GMI_CLK multiplexed OWR */ + + /* Camera interface aka video input */ +#ifdef COLIBRI_T20_VI + TEGRA_GPIO_PA7, /* SDIO3_CMD multiplexed VI_D6 */ + TEGRA_GPIO_PB4, /* SDIO3_DAT3 multiplexed VI_D7 */ +#else /* COLIBRI_T20_VI */ + TEGRA_GPIO_PL4, /* VI_D6 multiplexed SDIO3_CMD */ + TEGRA_GPIO_PL5, /* VI_D7 multiplexed SDIO3_DAT3 */ +#endif /* COLIBRI_T20_VI */ + + /* SODIMM pin 93 RDnWR */ +#if 1 + TEGRA_GPIO_PW0, /* gated GMI_WR_N multiplexed LCD_CS1_N */ +#endif + + /* SODIMM pin 44 L_BIAS configured as LCD data enable */ +#if 0 + TEGRA_GPIO_PJ1, /* LCD_M1 multiplexed LCD_DE */ +#else + TEGRA_GPIO_PW1, /* LCD_DE multiplexed LCD_M1 */ +#endif + + /* SODIMM pin 95 RDY */ +#if 1 + TEGRA_GPIO_PI7, /* GMI_IORDY multiplexed GMI_WAIT */ +#else + TEGRA_GPIO_PI5, /* GMI_WAIT multiplexed GMI_IORDY */ +#endif + + /* SODIMM pin 99 nPWE */ +#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE) + TEGRA_GPIO_PZ3, /* gated GMI_WR_N multiplexed LCD_WR_N */ +#endif + + /* 24-bit LCD lines */ +#if 0 + TEGRA_GPIO_PM2, /* SPI2_CS0_N multiplexed LCD_D18 */ + TEGRA_GPIO_PM3, /* SPI2_SCK multiplexed LCD_D19 */ + TEGRA_GPIO_PM4, /* SPI2_MISO multiplexed LCD_D20 */ + TEGRA_GPIO_PM5, /* SPI2_MOSI multiplexed LCD_D21 */ + TEGRA_GPIO_PM6, /* DAP2_DOUT multiplexed LCD_D22 */ + TEGRA_GPIO_PM7, /* DAP2_DIN multiplexed LCD_D23 */ +#else + TEGRA_GPIO_PX3, /* LCD_D18 multiplexed SPI2_CS0_N */ + TEGRA_GPIO_PX2, /* LCD_D19 multiplexed SPI2_SCK */ + TEGRA_GPIO_PX1, /* LCD_D20 multiplexed SPI2_MISO */ + TEGRA_GPIO_PX0, /* LCD_D21 multiplexed SPI2_MOSI */ + TEGRA_GPIO_PA5, /* LCD_D22 multiplexed DAP2_DOUT */ + TEGRA_GPIO_PA4, /* LCD_D23 multiplexed DAP2_DIN */ +#endif +}; + +static __initdata struct tegra_pingroup_config colibri_t20_pinmux[] = { +/* tegra_pingroup tegra_mux_func tegra_pullupdown tegra_tristate + TRISTATE here means output driver is tri-stated, even configuring GPIO function won't override this. + Tristating would significantly reduce I/O power consumption. */ + /* nRESET_OUT de-asserted further down below, GPIO I3, I4 and I6 */ + {TEGRA_PINGROUP_ATA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* nCSx, AD0, AD1, AD2, AD3, AD4, AD5, AD6 and AD7, nWR, nOE, GPIO K0, K1, K2, K3 and K4 */ + {TEGRA_PINGROUP_ATC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* AD8, AD9, AD10 and AD11 */ + {TEGRA_PINGROUP_ATD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* AD12, AD13, AD14 and AD15 */ + {TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* WM9715L XTL_IN */ +//audio sync clk could be either AC97 or PLLA_OUT0 +//SYNC_CLK_DOUBLER_ENB: Enable audio sync clk doubler. +// {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_AUDIO_SYNC, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* USB3340 REFCLK */ + {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* CLK_32K_IN pin pull-up/down control only */ + {TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK,TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO N0, N1, N2 and N3 */ + {TEGRA_PINGROUP_DAP1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO A2 and A3 */ + {TEGRA_PINGROUP_DAP2, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* A13, A14, A15 and A16, GPIO P4, P5, P6 and P7 */ + {TEGRA_PINGROUP_DAP4, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* DDC pins pulled up to avoid issues if no FFC cable is connected to X3 */ + {TEGRA_PINGROUP_DDC, TEGRA_MUX_I2C2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + /* Pull-up/down control only */ + {TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO D5 */ + {TEGRA_PINGROUP_DTA, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO T2 and T3 as KEY_FIND */ +#ifdef CONFIG_KEYBOARD_GPIO + {TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, +#else + {TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +#endif + {TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO L0, L1, L2, L3, L6 and L7 + GPIO L4 and L5 multiplexed with PWM<A> and PWM<D> */ + {TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* AX88772B V_BUS, WM9715L PENDOWN, GPIO A0, BB4 as KEY_VOLUMEUP and BB5 as KEY_VOLUMEDOWN */ +#ifdef CONFIG_KEYBOARD_GPIO + {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, +#else + {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +#endif + /* GPIO BB2 as KEY_BACK and BB3 as KEY_HOME */ +#ifdef CONFIG_KEYBOARD_GPIO + {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, +#else + {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +#endif + {TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* MM_CD */ + {TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI_INT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* BT_TXD, BT_RXD, BT_CTS and BT_RTS, GPIO K7 */ + {TEGRA_PINGROUP_GMC, TEGRA_MUX_UARTD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GMD, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO AA4, AA5, AA6 and AA7 */ +#ifndef SDHCI_8BIT + {TEGRA_PINGROUP_GME, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +#else + {TEGRA_PINGROUP_GME, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +#endif + /* A6, A7, A8, A9, A10, A11 and A12, GPIO U6 */ + {TEGRA_PINGROUP_GPU, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* AX88772B RESET_N and EXTWAKEUP_N */ + {TEGRA_PINGROUP_GPV, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* HDMI HOTPLUG_DETECT */ + {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* A0 */ + {TEGRA_PINGROUP_IRRX, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* A1 */ + {TEGRA_PINGROUP_IRTX, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCA, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCB, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCC, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCD, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCE, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCF, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO N4 */ + {TEGRA_PINGROUP_LCSN, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO N6 */ + {TEGRA_PINGROUP_LDC, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* Multiplexed RDnWR */ + {TEGRA_PINGROUP_LM0, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LM1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO B2 */ + {TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LPW1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* Multiplexed gated nPWE */ + {TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO Z4 */ + {TEGRA_PINGROUP_LSCK, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO N5 */ + {TEGRA_PINGROUP_LSDA, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO Z2 */ + {TEGRA_PINGROUP_LSDI, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* THERMD_ALERT */ + {TEGRA_PINGROUP_LVP0, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* OWR multiplexed with GMI_CLK */ + {TEGRA_PINGROUP_OWC, TEGRA_MUX_OWR, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + + /* Following five are for specific PMC pin pull-up/down control only */ + /* CLK_32K_OUT */ + {TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* SYS_CLK_REQ */ + {TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* CORE_PWR_REQ */ + {TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* CPU_PWR_REQ */ + {TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* PWR_INT_N pulled up */ + {TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + + /* Gating RDnWR, nPWE through GPIOs further down below */ + {TEGRA_PINGROUP_PTA, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* PWM3 */ + /* PWM<D> multiplexed with CIF_DD<6> */ + {TEGRA_PINGROUP_SDB, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO B6 and B7, PWM0 and PWM1 */ + /* PWM<A> multiplexed with CIF_DD<7> */ + {TEGRA_PINGROUP_SDC, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* PWM2 */ + {TEGRA_PINGROUP_SDD, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_UARTA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + + /* SPI4 */ + {TEGRA_PINGROUP_SLXA, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SLXD, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SLXK, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + + /* GPIO K6 as KEY_MENU multiplexed ACC1_DETECT */ + {TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* GPIO K5 multiplexed USB1_VBUS (USBC_DET) */ + {TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + + /* X0, X1, X2, X3, X4, X5, X6 and X7 */ + {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPID, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPIE, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPIF, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + + /* USBH_PEN */ + {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* USBH_OC */ + {TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + + /* ULPI data pins pulled up like on NVIDIA's Ventana reference platform */ + {TEGRA_PINGROUP_UAA, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_UAB, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + + /* WM9715L RESET#, USB3340 RESETB, WM9715L GENIRQ and GPIO V3 as KEY_POWER */ +#ifdef CONFIG_KEYBOARD_GPIO + {TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, +#else + {TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +#endif + /* STD_TXD and STD_RXD */ + {TEGRA_PINGROUP_UAD, TEGRA_MUX_IRDA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* A2 and A3 */ + {TEGRA_PINGROUP_UCA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* A4 and A5 */ + {TEGRA_PINGROUP_UCB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_UDA, TEGRA_MUX_ULPI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + + /* Following two are for specific DDR pin pull-up/down control only */ + {TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +}; + +#ifdef GMI_32BIT +/* 32-bit wide data and 28-bit wide address bus, more chip selects */ +static __initdata struct tegra_pingroup_config colibri_t20_widebus_pinmux[] = { + /* D28, D29, D30 and D31 */ + {TEGRA_PINGROUP_DAP1, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* AD20, AD21, AD22 and AD23 */ + {TEGRA_PINGROUP_GMA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* AD16, AD17, AD18 and AD19 */ + {TEGRA_PINGROUP_GMC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + /* nCS0 and nCS1 */ + {TEGRA_PINGROUP_GMD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +#ifndef SDHCI_8BIT + /* AD24, AD25, AD26 and AD27 */ + {TEGRA_PINGROUP_GME, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +#endif +}; +#endif /* GMI_32BIT */ + +int __init colibri_t20_pinmux_init(void) +{ + int i; + + tegra_pinmux_config_table(colibri_t20_pinmux, ARRAY_SIZE(colibri_t20_pinmux)); +#ifdef GMI_32BIT + tegra_pinmux_config_table(colibri_t20_widebus_pinmux, ARRAY_SIZE(colibri_t20_widebus_pinmux)); +#endif + tegra_drive_pinmux_config_table(colibri_t20_drive_pinmux, + ARRAY_SIZE(colibri_t20_drive_pinmux)); + + /* configure GPIO inputs on multiplexed balls to tri-state specific functions + instead of tri-stating whole groups */ + for(i = 0; i < ARRAY_SIZE(colibri_t20_gpio_input_pinmux); i++) { + gpio_request(colibri_t20_gpio_input_pinmux[i], "function tri-stated"); + gpio_direction_input(colibri_t20_gpio_input_pinmux[i]); + } + + /* un-resetting external devices via SODIMM pin 87 nRESET_OUT */ + gpio_request(TEGRA_GPIO_PI4, "SODIMM 87 nRESET_OUT"); + gpio_direction_output(TEGRA_GPIO_PI4, 1); + +#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE) + /* not tri-stating GMI_WR_N on SODIMM pin 99 nPWE */ + gpio_request(TEGRA_GPIO_PT5, "GMI_WR_N on 99"); + gpio_direction_output(TEGRA_GPIO_PT5, 0); +#else /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */ + /* tri-stating GMI_WR_N on SODIMM pin 99 nPWE */ + gpio_request(TEGRA_GPIO_PT5, "no GMI_WR_N on 99"); + gpio_direction_output(TEGRA_GPIO_PT5, 1); +#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */ + + /* not tri-stating GMI_WR_N on SODIMM pin 93 RDnWR */ + gpio_request(TEGRA_GPIO_PT6, "GMI_WR_N on 93 RDnWR"); + gpio_direction_output(TEGRA_GPIO_PT6, 0); + + return 0; +} diff --git a/arch/arm/mach-tegra/board-colibri_t20-power.c b/arch/arm/mach-tegra/board-colibri_t20-power.c new file mode 100644 index 000000000000..fb6e8e8e1bf3 --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t20-power.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2011 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/mfd/tps6586x.h> +#include <linux/platform_device.h> +#include <linux/regulator/machine.h> + +#include <mach/iomap.h> +#include <mach/irqs.h> + +#include "board-colibri_t20.h" +#include "board.h" +#include "fuse.h" +#include "gpio-names.h" +#include "pm.h" + +#define PMC_CTRL 0x0 +#define PMC_CTRL_INTR_LOW (1 << 17) + +/* VDD_CORE_1.2V */ +static struct regulator_consumer_supply tps658621_sm0_supply[] = { + REGULATOR_SUPPLY("vdd_core", NULL), +}; + +/* VDD_CPU_1.0V */ +static struct regulator_consumer_supply tps658621_sm1_supply[] = { + REGULATOR_SUPPLY("vdd_cpu", NULL), +}; + +/* VDD_DDR2_1.8V, LAN AX88772B VCC18A_ and NAND K9K8G08U0B VCC */ +static struct regulator_consumer_supply tps658621_sm2_supply[] = { + REGULATOR_SUPPLY("vdd_sm2", NULL), +}; + +/* unused */ +static struct regulator_consumer_supply tps658621_ldo0_supply[] = { + REGULATOR_SUPPLY("vdd_ldo0", NULL), +}; + +/* AVDD_PLL_1.1V and +3.3V_ENABLE_N switching via FET: AVDD_AUDIO_S and +3.3V: +SMSC USB3340 VBAT, VDDIO +VCC_LAN +VDDIO_AUDIO +VDDIO_BB +VDDIO_LCD +VDDIO_NAND +VDDIO_SDIO +VDDIO_UART +VDDIO_VI */ +static struct regulator_consumer_supply tps658621_ldo1_supply[] = { + REGULATOR_SUPPLY("vdd_ldo1", NULL), + REGULATOR_SUPPLY("avdd_pll", NULL), +}; + +/* VDD_RTC_1.2V */ +static struct regulator_consumer_supply tps658621_ldo2_supply[] = { + REGULATOR_SUPPLY("vdd_ldo2", NULL), + REGULATOR_SUPPLY("vdd_rtc", NULL), + REGULATOR_SUPPLY("vdd_aon", NULL), +}; + +/* unused */ +static struct regulator_consumer_supply tps658621_ldo3_supply[] = { + REGULATOR_SUPPLY("vdd_ldo3", NULL), +}; + +/* VDDIO_SYS_1.8V and VDDIO_PMIC */ +static struct regulator_consumer_supply tps658621_ldo4_supply[] = { + REGULATOR_SUPPLY("vdd_ldo4", NULL), + REGULATOR_SUPPLY("avdd_osc", NULL), +}; + +/* +3.3V_USB switched via FET: AVDD_USB, + +3.3V_FUSE switched via FET on FUSE_EN# (PMIC GPIO3)*/ +static struct regulator_consumer_supply tps658621_ldo5_supply[] = { + REGULATOR_SUPPLY("vdd_ldo5", NULL), + REGULATOR_SUPPLY("avdd_usb", NULL), + REGULATOR_SUPPLY("avdd_usb_pll", NULL), + /* fuse via separate GPIO FET (FUSE_ENABLE_N) */ + REGULATOR_SUPPLY("vdd_fuse", NULL), +}; + +/* AVDD_VDAC_2.85V */ +static struct regulator_consumer_supply tps658621_ldo6_supply[] = { + /* Off after boot, needs to be explicitly turned on! */ + REGULATOR_SUPPLY("vdd_ldo6", NULL), + REGULATOR_SUPPLY("avdd_vdac", NULL), +}; + +/* AVDD_HDMI_3.3V */ +static struct regulator_consumer_supply tps658621_ldo7_supply[] = { + REGULATOR_SUPPLY("vdd_ldo7", NULL), + REGULATOR_SUPPLY("avdd_hdmi", NULL), +}; + +/* AVDD_HDMI_PLL_1.8V */ +static struct regulator_consumer_supply tps658621_ldo8_supply[] = { + REGULATOR_SUPPLY("vdd_ldo8", NULL), + REGULATOR_SUPPLY("avdd_hdmi_pll", NULL), +}; + +/* VDDIO_RX_DDR_2.85V */ +static struct regulator_consumer_supply tps658621_ldo9_supply[] = { + REGULATOR_SUPPLY("vdd_ldo9", NULL), + REGULATOR_SUPPLY("vdd_ddr_rx", NULL), +}; + +static struct tps6586x_settings sm0_config = { + .sm_pwm_mode = PWM_DEFAULT_VALUE, + .slew_rate = SLEW_RATE_3520UV_PER_SEC, +}; + +static struct tps6586x_settings sm1_config = { + /* + * Current TPS6586x is known for having a voltage glitch if current load + * changes from low to high in auto PWM/PFM mode for CPU's Vdd line. + */ + .sm_pwm_mode = PWM_ONLY, + .slew_rate = SLEW_RATE_3520UV_PER_SEC, +}; + +#define REGULATOR_INIT(_id, _minmv, _maxmv, on, config) \ + { \ + .constraints = { \ + .min_uV = (_minmv)*1000, \ + .max_uV = (_maxmv)*1000, \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL | \ + REGULATOR_MODE_STANDBY), \ + .valid_ops_mask = (REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_STATUS | \ + REGULATOR_CHANGE_VOLTAGE), \ + .always_on = on, \ + .apply_uV = 1, \ + }, \ + .num_consumer_supplies = ARRAY_SIZE(tps658621_##_id##_supply),\ + .consumer_supplies = tps658621_##_id##_supply, \ + .driver_data = config, \ + } + +#define ON 1 +#define OFF 0 + +static struct regulator_init_data sm0_data = REGULATOR_INIT(sm0, 725, 1500, ON, &sm0_config); +static struct regulator_init_data sm1_data = REGULATOR_INIT(sm1, 725, 1500, ON, &sm1_config); +static struct regulator_init_data sm2_data = REGULATOR_INIT(sm2, 1700, 2475, ON, NULL); +static struct regulator_init_data ldo0_data = REGULATOR_INIT(ldo0, 1200, 3300, OFF, NULL); +static struct regulator_init_data ldo1_data = REGULATOR_INIT(ldo1, 725, 1500, ON, NULL); +static struct regulator_init_data ldo2_data = REGULATOR_INIT(ldo2, 725, 1500, OFF, NULL); +static struct regulator_init_data ldo3_data = REGULATOR_INIT(ldo3, 1250, 3300, OFF, NULL); +static struct regulator_init_data ldo4_data = REGULATOR_INIT(ldo4, 1700, 2475, ON, NULL); +static struct regulator_init_data ldo5_data = REGULATOR_INIT(ldo5, 1250, 3300, ON, NULL); +static struct regulator_init_data ldo6_data = REGULATOR_INIT(ldo6, 2850, 2850, OFF, NULL); +static struct regulator_init_data ldo7_data = REGULATOR_INIT(ldo7, 3300, 3300, OFF, NULL); +static struct regulator_init_data ldo8_data = REGULATOR_INIT(ldo8, 1800, 1800, OFF, NULL); +static struct regulator_init_data ldo9_data = REGULATOR_INIT(ldo9, 1250, 3300, OFF, NULL); + +static struct tps6586x_rtc_platform_data rtc_data = { + .irq = TEGRA_NR_IRQS + TPS6586X_INT_RTC_ALM1, + .start = { + .year = 2009, + .month = 1, + .day = 1, + }, + .cl_sel = TPS6586X_RTC_CL_SEL_1_5PF /* use lowest (external 20pF cap) */ +}; + +#define TPS_REG(_id, _data) \ + { \ + .id = TPS6586X_ID_##_id, \ + .name = "tps6586x-regulator", \ + .platform_data = _data, \ + } + +static struct tps6586x_subdev_info tps_devs[] = { + TPS_REG(SM_0, &sm0_data), + TPS_REG(SM_1, &sm1_data), + TPS_REG(SM_2, &sm2_data), + TPS_REG(LDO_0, &ldo0_data), + TPS_REG(LDO_1, &ldo1_data), + TPS_REG(LDO_2, &ldo2_data), + TPS_REG(LDO_3, &ldo3_data), + TPS_REG(LDO_4, &ldo4_data), + TPS_REG(LDO_5, &ldo5_data), + TPS_REG(LDO_6, &ldo6_data), + TPS_REG(LDO_7, &ldo7_data), + TPS_REG(LDO_8, &ldo8_data), + TPS_REG(LDO_9, &ldo9_data), + { + .id = 0, + .name = "tps6586x-rtc", + .platform_data = &rtc_data, + }, +}; + +static struct tps6586x_platform_data tps_platform = { + .irq_base = TPS6586X_INT_BASE, + .num_subdevs = ARRAY_SIZE(tps_devs), + .subdevs = tps_devs, + .gpio_base = TPS6586X_GPIO_BASE, + /* full PMIC power off decreases power consumption + but reset won't force a re-boot anymore */ + .use_power_off = true, +}; + +static struct i2c_board_info __initdata colibri_t20_regulators[] = { + { + I2C_BOARD_INFO("tps6586x", 0x34), + .irq = INT_EXTERNAL_PMU, + .platform_data = &tps_platform, + }, +}; + +static void colibri_t20_board_suspend(int lp_state, enum suspend_stage stg) +{ + if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_SUSPEND_BEFORE_CPU)) + tegra_console_uart_suspend(); +} + +static void colibri_t20_board_resume(int lp_state, enum resume_stage stg) +{ + if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_RESUME_AFTER_CPU)) + tegra_console_uart_resume(); +} + +static struct tegra_suspend_platform_data colibri_t20_suspend_data = { + /* + * Check power on time and crystal oscillator start time + * for appropriate settings. + */ + .cpu_timer = 2000, + .cpu_off_timer = 100, + .suspend_mode = TEGRA_SUSPEND_LP1, + .core_timer = 0x7e7e, + .core_off_timer = 0xf, + .corereq_high = false, + .sysclkreq_high = true, + .board_suspend = colibri_t20_board_suspend, + .board_resume = colibri_t20_board_resume, +}; + +int __init colibri_t20_regulator_init(void) +{ + void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); + u32 pmc_ctrl; +#if 0 +//currently LP0 is anyway not supported + void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804; + u32 minor; + + minor = (readl(chip_id) >> 16) & 0xf; + /* A03 (but not A03p) chips do not support LP0 */ + if (minor == 3 && !(tegra_spare_fuse(18) || tegra_spare_fuse(19))) + colibri_t20_suspend_data.suspend_mode = TEGRA_SUSPEND_LP1; +#endif + + /* configure the power management controller to trigger PMU + * interrupts when low */ + pmc_ctrl = readl(pmc + PMC_CTRL); + writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL); + + i2c_register_board_info(4, colibri_t20_regulators, ARRAY_SIZE(colibri_t20_regulators)); + +//none of the Tegra 2 boards currently do this +// regulator_has_full_constraints(); + + tegra_init_suspend(&colibri_t20_suspend_data); + + return 0; +} diff --git a/arch/arm/mach-tegra/board-colibri_t20.c b/arch/arm/mach-tegra/board-colibri_t20.c new file mode 100644 index 000000000000..470cc004165a --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t20.c @@ -0,0 +1,1579 @@ +/* + * arch/arm/mach-tegra/board-colibri_t20.c + * + * Copyright (c) 2011-2013 Toradex, Inc. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <linux/can/platform/mcp251x.h> +#include <linux/can/platform/sja1000.h> +#include <linux/clk.h> +#include <linux/colibri_usb.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/gpio_keys.h> +#include <linux/i2c.h> +#include <linux/i2c-tegra.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/leds_pwm.h> +#include <linux/lm95245.h> +#include <linux/memblock.h> +#include <linux/platform_data/tegra_usb.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/serial_8250.h> +#include <linux/spi/spi.h> +#if defined(CONFIG_SPI_GPIO) || defined(CONFIG_SPI_GPIO_MODULE) +#include <linux/spi/spi_gpio.h> +#endif +#include <linux/tegra_uart.h> +#include <linux/wm97xx.h> + +#include <mach/gpio.h> +#include <mach/nand.h> +#include <mach/sdhci.h> +#include <mach/usb_phy.h> +#include <mach/w1.h> + +#include <media/soc_camera.h> +#include <media/tegra_v4l2_camera.h> +#include <linux/input/fusion_F0710A.h> + +#include "board-colibri_t20.h" +#include "board.h" +#include "clock.h" +#include "cpu-tegra.h" +#include "devices.h" +#include "gpio-names.h" +#include "pm.h" +#include "wakeups-t2.h" + +//from former drivers/mtd/maps/tegra_nor.h +#define TEGRA_GMI_PHYS 0x70009000 +#define TEGRA_GMI_BASE IO_TO_VIRT(TEGRA_GMI_PHYS) +#define TEGRA_SNOR_CONFIG_REG (TEGRA_GMI_BASE + 0x00) + +//from drivers/mtd/maps/tegra_nor.c +#define __BITMASK0(len) (BIT(len) - 1) +#define REG_FIELD(val, start, len) (((val) & __BITMASK0(len)) << (start)) + +#define TEGRA_SNOR_CONFIG_GO BIT(31) +#define TEGRA_SNOR_CONFIG_SNOR_CS(val) REG_FIELD((val), 4, 3) + +/* ADC */ + +static struct wm97xx_batt_pdata colibri_t20_adc_pdata = { + .batt_aux = WM97XX_AUX_ID1, /* AD0 - ANALOG_IN0 */ + .temp_aux = WM97XX_AUX_ID2, /* AD1 - ANALOG_IN1 */ + .charge_gpio = -1, + .batt_div = 1, + .batt_mult = 1, + .temp_div = 1, + .temp_mult = 1, + .batt_name = "colibri_t20-analog_inputs", +}; + +static struct wm97xx_pdata colibri_t20_wm97xx_pdata = { + .batt_pdata = &colibri_t20_adc_pdata, +}; + +/* Audio */ + +static struct platform_device colibri_t20_audio_device = { + .name = "colibri_t20-snd-wm9715l", + .id = 0, +}; + +void *get_colibri_t20_audio_platform_data(void) +{ + return &colibri_t20_wm97xx_pdata; +} +EXPORT_SYMBOL(get_colibri_t20_audio_platform_data); + +/* Camera */ + +#ifdef CONFIG_TEGRA_CAMERA +static struct platform_device tegra_camera = { + .name = "tegra_camera", + .id = -1, +}; +#endif /* CONFIG_TEGRA_CAMERA */ + +#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE) +static void tegra_camera_disable(struct nvhost_device *ndev) +{ +} + +static int tegra_camera_enable(struct nvhost_device *ndev) +{ + return 0; +} + +static struct tegra_camera_platform_data tegra_camera_platform_data = { + .disable_camera = tegra_camera_disable, + .enable_camera = tegra_camera_enable, + .flip_h = 0, + .flip_v = 0, + .port = TEGRA_CAMERA_PORT_VIP, +}; + +#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE) +static struct i2c_board_info camera_i2c_max9526 = { + I2C_BOARD_INFO("max9526", 0x21), +}; + +static struct soc_camera_link iclink_max9526 = { + .board_info = &camera_i2c_max9526, + .bus_id = -1, /* This must match the .id of tegra_vi01_device */ + .i2c_adapter_id = 0, +}; + +static struct platform_device soc_camera_max9526 = { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &iclink_max9526, + }, +}; +#endif /* CONFIG_SOC_CAMERA_MAX9526 | CONFIG_SOC_CAMERA_MAX9526_MODULE */ + +#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE) +static struct i2c_board_info camera_i2c_adv7180 = { + I2C_BOARD_INFO("adv7180", 0x21), +}; + +static struct soc_camera_link iclink_adv7180 = { + .board_info = &camera_i2c_adv7180, + .bus_id = -1, /* This must match the .id of tegra_vi01_device */ + .i2c_adapter_id = 0, +}; + +static struct platform_device soc_camera_adv7180 = { + .name = "soc-camera-pdrv", + .id = 1, + .dev = { + .platform_data = &iclink_adv7180, + }, +}; +#endif /* CONFIG_VIDEO_ADV7180 | CONFIG_VIDEO_ADV7180_MODULE */ +#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */ + +/* CAN */ +#if ((defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)) && \ + (defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE))) + #error either enable MCP251X or SJA1000 but not both +#endif + +#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE) +/* Colibri EvalBoard V3.1a/MECS Tellurium xPOD CAN module featuring MCP2515 SPI CAN controller */ + +#ifdef MECS_TELLURIUM_XPOD2 +#define CAN_CS_GPIO TEGRA_GPIO_PB7 /* SSPFRM2 */ +#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PK3 /* active low interrupt (MCP2515 nINT) */ +#define CAN_RESET_GPIO TEGRA_GPIO_PK2 /* active high reset (not MCP2515 nRESET) */ +#else +#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PA0 /* active low interrupt (MCP2515 nINT) */ +#define CAN_RESET_GPIO TEGRA_GPIO_PK4 /* active high reset (not MCP2515 nRESET) */ +#endif + +static int __init colibri_t20_mcp2515_setup(struct spi_device *spi) +{ + int gpio_status; + + printk("Colibri EvalBoard V3.1a/MECS Tellurium xPOD CAN Initialisation\n"); + + /* configure MCP2515 reset line as output and pull high into reset */ + gpio_status = gpio_request(CAN_RESET_GPIO, "CAN_RESET_GPIO"); + if (gpio_status < 0) + pr_warning("CAN_RESET_GPIO request GPIO FAILED\n"); + gpio_status = gpio_direction_output(CAN_RESET_GPIO, 1); + if (gpio_status < 0) + pr_warning("CAN_RESET_GPIO request GPIO DIRECTION FAILED\n"); + + udelay(2); + + /* pull out of reset */ + gpio_set_value(CAN_RESET_GPIO, 0); + + return 0; +} + +static struct mcp251x_platform_data mcp251x_pdata = { + .board_specific_setup = colibri_t20_mcp2515_setup, + .oscillator_frequency = 16000000, + .power_enable = NULL, + .transceiver_enable = NULL +}; + +static struct spi_board_info mcp251x_board_info[] = { + { +#ifndef MECS_TELLURIUM_XPOD2 + .bus_num = 3, +#else + .bus_num = 4, +#endif + .chip_select = 0, +#ifdef MECS_TELLURIUM_XPOD2 + .controller_data = (void *) CAN_CS_GPIO, +#else +// .controller_data = , +#endif + .max_speed_hz = 10000000, + .modalias = "mcp2515", + .platform_data = &mcp251x_pdata, + }, +}; + +static void __init colibri_t20_mcp2515_can_init(void) +{ + mcp251x_board_info[0].irq = gpio_to_irq(CAN_INTERRUPT_GPIO); + spi_register_board_info(mcp251x_board_info, ARRAY_SIZE(mcp251x_board_info)); +} +#else /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */ +#define colibri_t20_mcp2515_can_init() do {} while (0) +#endif /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */ + +#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE) +#define CAN_BASE_TEG 0xd0000000 /* GMI_CS4_N */ +static struct resource colibri_can_resource[] = { + [0] = { + .start = CAN_BASE_TEG, /* address */ + .end = CAN_BASE_TEG + 0xff, /* data */ + .flags = IORESOURCE_MEM, + }, + [1] = { + /* interrupt assigned during initialisation */ + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, + } +}; + +static struct sja1000_platform_data colibri_can_platdata = { + .osc_freq = 24000000, + .ocr = (OCR_MODE_NORMAL | OCR_TX0_PUSHPULL), + .cdr = CDR_CLK_OFF | /* Clock off (CLKOUT pin) */ + CDR_CBP, /* CAN input comparator bypass */ +}; + +static struct platform_device colibri_can_device = { + .name = "sja1000_platform", + .id = 0, + .num_resources = ARRAY_SIZE(colibri_can_resource), + .resource = colibri_can_resource, + .dev = { + .platform_data = &colibri_can_platdata, + } +}; +#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */ + +/* Clocks */ +static struct tegra_clk_init_table colibri_t20_clk_init_table[] __initdata = { + /* name parent rate enabled */ + {"blink", "clk_32k", 32768, false}, + /* SMSC3340 REFCLK 24 MHz */ + {"pll_p_out4", "pll_p", 24000000, true}, + {"pwm", "clk_m", 0, false}, + {"spdif_out", "pll_a_out0", 0, false}, + +//required otherwise getting disabled by "Disabling clocks left on by +//bootloader" stage + {"uarta", "pll_p", 216000000, true}, + +//required otherwise uses pll_p_out4 as parent and changing its rate to 72 MHz + {"sclk", "pll_p_out3", 108000000, true}, + + /* AC97 incl. touch (note: unfortunately no clk source mux exists) */ + {"ac97", "pll_a_out0", 24576000, true}, + + /* WM9715L XTL_IN 24.576 MHz */ +//[ 0.372722] Unable to set parent pll_a_out0 of clock cdev1: -38 +// {"cdev1", "pll_a_out0", 24576000, true}, +// {"pll_a_out0", "pll_a", 24576000, true}, + + {"vde", "pll_c", 240000000, false}, + + {"ndflash", "pll_p", 108000000, false}, + {"nor", "pll_p", 86500000, true}, + +//[ 2.284308] kernel BUG at drivers/spi/spi-tegra.c:254! +//[ 2.289454] Unable to handle kernel NULL pointer dereference at virtual +// address 00000000 + {"sbc4", "pll_p", 12000000, false}, + + {NULL, NULL, 0, 0}, +}; + +/* GPIO */ + +static struct gpio colibri_t20_gpios[] = { +#if !defined(IRIS) && !defined(CONFIG_CAN_MCP251X) && \ + !defined(CONFIG_CAN_MCP251X_MODULE) && \ + !defined(CONFIG_CAN_SJA1000) && \ + !defined(CONFIG_CAN_SJA1000_MODULE) +//conflicts with CAN interrupt on Colibri Evaluation Board and MECS Tellurium +//xPOD1 CAN +//conflicts with DAC_PSAVE# on Iris + {TEGRA_GPIO_PA0, GPIOF_IN, "SODIMM pin 73"}, +#endif + {TEGRA_GPIO_PA2, GPIOF_IN, "SODIMM pin 186"}, + {TEGRA_GPIO_PA3, GPIOF_IN, "SODIMM pin 184"}, + {TEGRA_GPIO_PB2, GPIOF_IN, "SODIMM pin 154"}, +#if !defined(CONFIG_SPI_GPIO) && !defined(CONFIG_SPI_GPIO_MODULE) +//conflicts with MECS Tellurium xPOD2 SSPCLK2 + {TEGRA_GPIO_PB6, GPIOF_IN, "SODIMM pin 55"}, +#endif +#ifndef MECS_TELLURIUM_XPOD2 +//conflicts with MECS Tellurium xPOD2 SSPFRM2 + {TEGRA_GPIO_PB7, GPIOF_IN, "SODIMM pin 63"}, +#endif +#ifndef COLIBRI_T20_VI + {TEGRA_GPIO_PD5, GPIOF_IN, "SODI-98, Iris X16-13"}, + {TEGRA_GPIO_PD6, GPIOF_IN, "SODIMM pin 81"}, + {TEGRA_GPIO_PD7, GPIOF_IN, "SODIMM pin 94"}, +#endif + {TEGRA_GPIO_PI3, GPIOF_IN, "SODIMM pin 130"}, + {TEGRA_GPIO_PI6, GPIOF_IN, "SODIMM pin 132"}, +//conflicts with GMI_ADV_N used for multiplexed address/data bus + {TEGRA_GPIO_PK0, GPIOF_IN, "SODIMM pin 150"}, +//multiplexed OWR + {TEGRA_GPIO_PK1, GPIOF_IN, "SODIMM pin 152"}, +#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE) +//conflicts with CAN reset on MECS Tellurium xPOD1 CAN + {TEGRA_GPIO_PK4, GPIOF_IN, "SODIMM pin 106"}, +#endif +// {TEGRA_GPIO_PK5, GPIOF_IN, "USBC_DET"}, +#ifndef CONFIG_KEYBOARD_GPIO +//conflicts with menu key + {TEGRA_GPIO_PK6, GPIOF_IN, "SODIMM pin 135"}, +#endif +#ifndef COLIBRI_T20_VI + {TEGRA_GPIO_PL0, GPIOF_IN, "SOD-101, Iris X16-16"}, + {TEGRA_GPIO_PL1, GPIOF_IN, "SOD-103, Iris X16-15"}, +//conflicts with Ethernet interrupt on Protea + {TEGRA_GPIO_PL2, GPIOF_IN, "SODI-79, Iris X16-19"}, + {TEGRA_GPIO_PL3, GPIOF_IN, "SODI-97, Iris X16-17"}, + {TEGRA_GPIO_PL6, GPIOF_IN, "SODI-85, Iris X16-18"}, + {TEGRA_GPIO_PL7, GPIOF_IN, "SODIMM pin 65"}, +#endif + +//multiplexed SPI2_CS0_N, SPI2_MISO, SPI2_MOSI and SPI2_SCK + {TEGRA_GPIO_PM2, GPIOF_IN, "SODIMM pin 136"}, + {TEGRA_GPIO_PM3, GPIOF_IN, "SODIMM pin 138"}, + {TEGRA_GPIO_PM4, GPIOF_IN, "SODIMM pin 140"}, + {TEGRA_GPIO_PM5, GPIOF_IN, "SODIMM pin 142"}, + +#ifndef GMI_32BIT + {TEGRA_GPIO_PN0, GPIOF_IN, "SODIMM pin 174"}, + {TEGRA_GPIO_PN1, GPIOF_IN, "SODIMM pin 176"}, + {TEGRA_GPIO_PN2, GPIOF_IN, "SODIMM pin 178"}, + {TEGRA_GPIO_PN3, GPIOF_IN, "SODIMM pin 180"}, +#endif + {TEGRA_GPIO_PN4, GPIOF_IN, "SODIMM pin 160"}, + {TEGRA_GPIO_PN5, GPIOF_IN, "SODIMM pin 158"}, + {TEGRA_GPIO_PN6, GPIOF_IN, "SODIMM pin 162"}, +//conflicts with ADDRESS13 + {TEGRA_GPIO_PP4, GPIOF_IN, "SODIMM pin 120"}, +//conflicts with ADDRESS14 + {TEGRA_GPIO_PP5, GPIOF_IN, "SODIMM pin 122"}, +//conflicts with ADDRESS15 + {TEGRA_GPIO_PP6, GPIOF_IN, "SODIMM pin 124"}, + {TEGRA_GPIO_PP7, GPIOF_IN, "SODIMM pin 188"}, +#ifndef COLIBRI_T20_VI + {TEGRA_GPIO_PT0, GPIOF_IN, "SODIMM pin 96"}, + {TEGRA_GPIO_PT1, GPIOF_IN, "SODIMM pin 75"}, +#endif + {TEGRA_GPIO_PT2, GPIOF_IN, "SODIMM pin 69"}, +#ifndef CONFIG_KEYBOARD_GPIO +//conflicts with find key + {TEGRA_GPIO_PT3, GPIOF_IN, "SODIMM pin 77"}, +#endif +//conflicts with BL_ON +// {TEGRA_GPIO_PT4, GPIOF_IN, "SODIMM pin 71"}, +//conflicts with ADDRESS12 + {TEGRA_GPIO_PU6, GPIOF_IN, "SODIMM pin 118"}, +#ifndef CONFIG_KEYBOARD_GPIO +//conflicts with power key (WAKE1) + {TEGRA_GPIO_PV3, GPIOF_IN, "SODI-45, Iris X16-20"}, +#endif + + {TEGRA_GPIO_PX4, GPIOF_IN, "SODIMM pin 134"}, + {TEGRA_GPIO_PX6, GPIOF_IN, "102, I X13 ForceOFF#"}, + {TEGRA_GPIO_PX7, GPIOF_IN, "104, I X14 ForceOFF#"}, + {TEGRA_GPIO_PZ2, GPIOF_IN, "SODIMM pin 156"}, + {TEGRA_GPIO_PZ4, GPIOF_IN, "SODIMM pin 164"}, +#if !defined(GMI_32BIT) && !defined SDHCI_8BIT + {TEGRA_GPIO_PAA4, GPIOF_IN, "SODIMM pin 166"}, + {TEGRA_GPIO_PAA5, GPIOF_IN, "SODIMM pin 168"}, + {TEGRA_GPIO_PAA6, GPIOF_IN, "SODIMM pin 170"}, + {TEGRA_GPIO_PAA7, GPIOF_IN, "SODIMM pin 172"}, +#endif +#ifndef CONFIG_KEYBOARD_GPIO +//conflicts with back key + {TEGRA_GPIO_PBB2, GPIOF_IN, "SOD-133, Iris X16-14"}, +//conflicts with home key + {TEGRA_GPIO_PBB3, GPIOF_IN, "SODIMM pin 127"}, +//conflicts with volume up key + {TEGRA_GPIO_PBB4, GPIOF_IN, "SODIMM pin 22"}, +//conflicts with volume down key + {TEGRA_GPIO_PBB5, GPIOF_IN, "SODIMM pin 24"}, +#endif +}; + +static void colibri_t20_gpio_init(void) +{ + int i = 0; + int length = sizeof(colibri_t20_gpios) / sizeof(struct gpio); + int err = 0; + + for (i = 0; i < length; i++) { + err = gpio_request_one(colibri_t20_gpios[i].gpio, + colibri_t20_gpios[i].flags, + colibri_t20_gpios[i].label); + + if (err) { + pr_warning("gpio_request(%s) failed, err = %d", + colibri_t20_gpios[i].label, err); + } else { + gpio_export(colibri_t20_gpios[i].gpio, true); + } + } +} + +/* + * Fusion touch screen GPIOs (using Toradex display/touch adapater) + * Iris X16-38, SODIMM pin 28 (PWM B), pen down interrupt + * Iris X16-39, SODIMM pin 30 (PWM C), reset + * gpio_request muxes the GPIO function automatically, we only have to make + * sure input/output muxing is done here... + */ +static struct fusion_f0710a_init_data colibri_fusion_pdata = { + .pinmux_fusion_pins = NULL, + .gpio_int = TEGRA_GPIO_PB5, /* SO-DIMM 28: Pen down interrupt */ + .gpio_reset = TEGRA_GPIO_PA6, /* SO-DIMM 30: Reset interrupt */ +}; + +/* I2C */ + +/* GEN1_I2C: I2C_SDA/SCL on SODIMM pin 194/196 (e.g. RTC on carrier board) */ +static struct i2c_board_info colibri_t20_i2c_bus1_board_info[] __initdata = { + { + /* M41T0M6 real time clock on Iris carrier board */ + I2C_BOARD_INFO("rtc-ds1307", 0x68), + .type = "m41t00", + }, + { + /* TouchRevolution Fusion 7 and 10 multi-touch controller */ + I2C_BOARD_INFO("fusion_F0710A", 0x10), + .platform_data = &colibri_fusion_pdata, + }, +}; + +static struct tegra_i2c_platform_data colibri_t20_i2c1_platform_data = { + .adapter_nr = 0, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {400000, 0}, + .bus_count = 1, + .scl_gpio = {I2C_SCL, 0}, + .sda_gpio = {I2C_SDA, 0}, + .slave_addr = 0x00FC, +}; + +/* GEN2_I2C: unused */ + +/* DDC_CLOCK/DATA on X3 pin 15/16 (e.g. display EDID) */ +static const struct tegra_pingroup_config i2c2_ddc = { + .pingroup = TEGRA_PINGROUP_DDC, + .func = TEGRA_MUX_I2C2, +}; + +static struct tegra_i2c_platform_data colibri_t20_i2c2_platform_data = { + .adapter_nr = 1, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {10000, 10000}, + .bus_count = 1, + .slave_addr = 0x00FC, +}; + +/* PWR_I2C: power I2C to PMIC and temperature sensor */ + +static void lm95245_probe_callback(struct device *dev); + +static struct lm95245_platform_data colibri_t20_lm95245_pdata = { + .enable_os_pin = true, + .probe_callback = lm95245_probe_callback, +}; + +static struct i2c_board_info colibri_t20_i2c_bus4_board_info[] __initdata = { + { + /* LM95245 temperature sensor */ + I2C_BOARD_INFO("lm95245", 0x4c), + .platform_data = &colibri_t20_lm95245_pdata, + }, +}; + +static struct tegra_i2c_platform_data colibri_t20_dvc_platform_data = { + .adapter_nr = 4, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {400000, 0}, + .bus_count = 1, + .is_dvc = true, + .scl_gpio = {PWR_I2C_SCL, 0}, + .sda_gpio = {PWR_I2C_SDA, 0}, +}; + +static void colibri_t20_i2c_init(void) +{ + tegra_i2c_device1.dev.platform_data = &colibri_t20_i2c1_platform_data; + tegra_i2c_device2.dev.platform_data = &colibri_t20_i2c2_platform_data; + tegra_i2c_device4.dev.platform_data = &colibri_t20_dvc_platform_data; + + platform_device_register(&tegra_i2c_device1); + platform_device_register(&tegra_i2c_device2); + platform_device_register(&tegra_i2c_device4); + + i2c_register_board_info(0, colibri_t20_i2c_bus1_board_info, + ARRAY_SIZE(colibri_t20_i2c_bus1_board_info)); + i2c_register_board_info(4, colibri_t20_i2c_bus4_board_info, + ARRAY_SIZE(colibri_t20_i2c_bus4_board_info)); +} + +/* Keys + * Note: active-low means pull-ups required on carrier board resp. via + * pin-muxing + * Note2: power-key active-high due to EvalBoard v3.1a having 100 K pull-down + * on SODIMM pin 45 + * Note3: menu-key active-high due to strong pull-down on multiplexed + * ACC1_DETECT + * Note4: Wake keys need to be supported by hardware, see wakeups-t2.h + */ + +#ifdef CONFIG_KEYBOARD_GPIO +#define GPIO_KEY(_id, _gpio, _lowactive, _iswake) \ + { \ + .code = _id, \ + .gpio = TEGRA_GPIO_##_gpio, \ + .active_low = _lowactive, \ + .desc = #_id, \ + .type = EV_KEY, \ + .wakeup = _iswake, \ + .debounce_interval = 10, \ + } + +static struct gpio_keys_button colibri_t20_keys[] = { + GPIO_KEY(KEY_FIND, PT3, 1, 0), /* SODIMM pin 77 */ + GPIO_KEY(KEY_HOME, PBB3, 1, 0), /* SODIMM pin 127 */ + GPIO_KEY(KEY_BACK, PBB2, 1, 0), /* SODIMM pin 133, + Iris X16-14 */ + GPIO_KEY(KEY_VOLUMEUP, PBB4, 1, 0), /* SODIMM pin 22 */ + GPIO_KEY(KEY_VOLUMEDOWN, PBB5, 1, 0), /* SODIMM pin 24 */ + GPIO_KEY(KEY_POWER, PV3, 0, 1), /* SODIMM pin 45, + Iris X16-20 */ + GPIO_KEY(KEY_MENU, PK6, 0, 0), /* SODIMM pin 135 */ +}; + +#define PMC_WAKE_STATUS 0x14 + +static int colibri_t20_wakeup_key(void) +{ + unsigned long status = + readl(IO_ADDRESS(TEGRA_PMC_BASE) + PMC_WAKE_STATUS); + + return (status & (1 << TEGRA_WAKE_GPIO_PV3)) ? + KEY_POWER : KEY_RESERVED; +} + +static struct gpio_keys_platform_data colibri_t20_keys_platform_data = { + .buttons = colibri_t20_keys, + .nbuttons = ARRAY_SIZE(colibri_t20_keys), + .wakeup_key = colibri_t20_wakeup_key, +}; + +static struct platform_device colibri_t20_keys_device = { + .name = "gpio-keys", + .id = 0, + .dev = { + .platform_data = &colibri_t20_keys_platform_data, + }, +}; +#endif /* CONFIG_KEYBOARD_GPIO */ + +#ifndef GMI_32BIT +/* MMC/SD */ + +static struct tegra_sdhci_platform_data colibri_t20_sdhci_platform_data = { + .cd_gpio = MMC_CD, +#ifndef SDHCI_8BIT + .is_8bit = 0, +#else + .is_8bit = 1, +#endif + .power_gpio = -1, + .wp_gpio = -1, +}; + +int __init colibri_t20_sdhci_init(void) +{ + tegra_sdhci_device4.dev.platform_data = + &colibri_t20_sdhci_platform_data; + platform_device_register(&tegra_sdhci_device4); + + return 0; +} +#endif /* !GMI_32BIT */ + +/* NAND */ + +static struct tegra_nand_chip_parms nand_chip_parms[] = { + /* Micron MT29F4G08ABBDAH4 */ + [0] = { + .vendor_id = 0x2C, + .device_id = 0xAC, + .read_id_fourth_byte = 0x15, + .capacity = 512, + .timing = { + .trp = 12, + .trh = 10, /* tREH */ + .twp = 12, + .twh = 10, + .tcs = 20, /* Max(tCS, tCH, tALS, tALH) */ + .twhr = 80, + .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */ + .twb = 100, + .trp_resp = 12, /* tRP */ + .tadl = 70, + }, + }, + /* Micron MT29F4G08ABBEAH4 */ + [1] = { + .vendor_id = 0x2C, + .device_id = 0xAC, + .read_id_fourth_byte = 0x26, + .capacity = 512, + .timing = { + .trp = 15, + .trh = 10, /* tREH */ + .twp = 15, + .twh = 10, + .tcs = 25, /* Max(tCS, tCH, tALS, tALH) */ + .twhr = 80, + .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */ + .twb = 100, + .trp_resp = 15, /* tRP */ + .tadl = 100, + }, + }, + /* Micron MT29F8G08ABCBB on Colibri T20 before V1.2 */ + [2] = { + .vendor_id = 0x2C, + .device_id = 0x38, + .read_id_fourth_byte = 0x26, + .capacity = 1024, + .timing = { + /* timing mode 4 */ + .trp = 12, + .trh = 10, /* tREH */ + .twp = 12, + .twh = 10, + .tcs = 20, /* Max(tCS, tCH, tALS, tALH) */ + .twhr = 60, + .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */ + .twb = 100, + .trp_resp = 12, /* tRP */ + .tadl = 70, + }, + }, + /* Micron MT29F8G08ADBDAH4 */ + [3] = { + .vendor_id = 0x2C, + .device_id = 0xA3, + .read_id_fourth_byte = 0x15, + .capacity = 1024, + .timing = { + .trp = 12, + .trh = 10, /* tREH */ + .twp = 12, + .twh = 10, + .tcs = 20, /* Max(tCS, tCH, tALS, tALH) */ + .twhr = 80, + .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */ + .twb = 100, + .trp_resp = 12, /* tRP */ + .tadl = 70, + }, + }, + /* Micron MT29F8G08ABBCA */ + [4] = { + .vendor_id = 0x2C, + .device_id = 0xA3, + .read_id_fourth_byte = 0x26, + .capacity = 1024, + .timing = { + .trp = 15, + .trh = 10, /* tREH */ + .twp = 15, + .twh = 10, + .tcs = 25, /* Max(tCS, tCH, tALS, tALH) */ + .twhr = 80, + .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */ + .twb = 100, + .trp_resp = 15, /* tRP */ + .tadl = 100, + }, + }, + /* Samsung K9K8G08U0B */ + [5] = { + .vendor_id = 0xec, + .device_id = 0xd3, + .read_id_fourth_byte = 0x95, + .capacity = 1024, + .timing = { + .trp = 12, /* tRP, ND_nRE pulse width */ + .trh = 100, /* tRHZ, ND_nRE high + duration */ + .twp = 12, /* tWP, ND_nWE pulse time */ + .twh = 10, /* tWH, ND_nWE high duration */ + .tcs = 20, /* Max(tCS, tCH, tALS, tALH) */ + .twhr = 60, /* tWHR, ND_nWE high to ND_nRE + low delay for status read */ + .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */ + .twb = 100, + .trp_resp = 12, /* tRP */ + .tadl = 70, + }, + }, +}; + +struct tegra_nand_platform colibri_t20_nand_data = { + .max_chips = 8, + .chip_parms = nand_chip_parms, + .nr_chip_parms = ARRAY_SIZE(nand_chip_parms), + .wp_gpio = NAND_WP_N, +}; + +static struct resource resources_nand[] = { + [0] = { + .start = INT_NANDFLASH, + .end = INT_NANDFLASH, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device tegra_nand_device = { + .name = "tegra_nand", + .id = -1, + .num_resources = ARRAY_SIZE(resources_nand), + .resource = resources_nand, + .dev = { + .platform_data = &colibri_t20_nand_data, + }, +}; + +/* PWM LEDs */ +static struct led_pwm tegra_leds_pwm[] = { +#ifdef MECS_TELLURIUM + { + .name = "PWM<A>", + .pwm_id = 0, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, +#endif /* MECS_TELLURIUM */ + { + .name = "PWM<B>", + .pwm_id = 1, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, +#ifndef MECS_TELLURIUM + { + .name = "PWM<C>", + .pwm_id = 2, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, +#endif /* !MECS_TELLURIUM */ + { + .name = "PWM<D>", + .pwm_id = 3, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, +}; + +static struct led_pwm_platform_data tegra_leds_pwm_data = { + .num_leds = ARRAY_SIZE(tegra_leds_pwm), + .leds = tegra_leds_pwm, +}; + +static struct platform_device tegra_led_pwm_device = { + .name = "leds_pwm", + .id = -1, + .dev = { + .platform_data = &tegra_leds_pwm_data, + }, +}; + +/* RTC */ + +#ifdef CONFIG_RTC_DRV_TEGRA +static struct resource tegra_rtc_resources[] = { + [0] = { + .start = TEGRA_RTC_BASE, + .end = TEGRA_RTC_BASE + TEGRA_RTC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_RTC, + .end = INT_RTC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device tegra_rtc_device = { + .name = "tegra_rtc", + .id = -1, + .resource = tegra_rtc_resources, + .num_resources = ARRAY_SIZE(tegra_rtc_resources), +}; +#endif /* CONFIG_RTC_DRV_TEGRA */ + +/* SPI */ + +#if defined(CONFIG_SPI_GPIO) || defined(CONFIG_SPI_GPIO_MODULE) +#ifdef MECS_TELLURIUM_XPOD2 +struct spi_gpio_platform_data xpod2_spi_platform_data = { + .sck = TEGRA_GPIO_PB6, /* SSPCLK2 */ + .mosi = TEGRA_GPIO_PW2, /* SSPTXD2 */ + .miso = TEGRA_GPIO_PW3, /* SSPRXD2 */ + .num_chipselect = 1, +}; + +static struct platform_device xpod2_spi_device = { + .name = "spi_gpio", + .id = 4, + .dev = { + .platform_data = &xpod2_spi_platform_data, + } +}; +#endif /* MECS_TELLURIUM_XPOD2 */ +#endif /* CONFIG_SPI_GPIO | CONFIG_SPI_GPIO_MODULE */ + +#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV) +static struct spi_board_info tegra_spi_devices[] __initdata = { + { + .bus_num = 3, /* SPI4: Colibri SSP */ +#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE) + .chip_select = 0, +#else /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */ + .chip_select = 1, +#endif /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */ + .irq = 0, + .max_speed_hz = 50000000, + .modalias = "spidev", + .mode = SPI_MODE_0, + .platform_data = NULL, + }, +}; + +static void __init colibri_t20_register_spidev(void) +{ + spi_register_board_info(tegra_spi_devices, + ARRAY_SIZE(tegra_spi_devices)); +} +#else /* CONFIG_SPI_TEGRA & CONFIG_SPI_SPIDEV */ +#define colibri_t20_register_spidev() do {} while (0) +#endif /* CONFIG_SPI_TEGRA & CONFIG_SPI_SPIDEV */ + +/* Thermal throttling + Note: As our hardware only allows triggering an interrupt on + over-temperature shutdown we first use it to catch entering throttle + and only then set it up to catch an actual over-temperature shutdown. + While throttling we setup a workqueue to catch leaving it again. */ + +static int colibri_t20_shutdown_temp = 115000; +static int colibri_t20_throttle_hysteresis = 3000; +static int colibri_t20_throttle_temp = 90000; +static struct device *lm95245_device = NULL; +static int thermd_alert_irq_disabled = 0; +struct work_struct thermd_alert_work; +struct workqueue_struct *thermd_alert_workqueue; + +/* Over-temperature shutdown OS pin GPIO interrupt handler */ +static irqreturn_t thermd_alert_irq(int irq, void *data) +{ + disable_irq_nosync(irq); + thermd_alert_irq_disabled = 1; + queue_work(thermd_alert_workqueue, &thermd_alert_work); + + return IRQ_HANDLED; +} + +/* Gets both entered by THERMD_ALERT GPIO interrupt as well as re-scheduled + while throttling. */ +static void thermd_alert_work_func(struct work_struct *work) +{ + int temp = 0; + + lm95245_get_remote_temp(lm95245_device, &temp); + + if (temp > colibri_t20_shutdown_temp) { + /* First check for hardware over-temperature condition mandating + immediate shutdown */ + pr_err("over-temperature condition %d degC reached, initiating " + "immediate shutdown", temp); + kernel_power_off(); + } else if (temp < colibri_t20_throttle_temp - + colibri_t20_throttle_hysteresis) { + /* Make sure throttling gets disabled again */ + if (tegra_is_throttling()) { + tegra_throttling_enable(false); + lm95245_set_remote_os_limit(lm95245_device, + colibri_t20_throttle_temp); + } + } else if (temp < colibri_t20_throttle_temp) { + /* Operating within hysteresis so keep re-scheduling to catch + leaving below throttle again */ + if (tegra_is_throttling()) { + msleep(100); + queue_work(thermd_alert_workqueue, &thermd_alert_work); + } + } else if (temp >= colibri_t20_throttle_temp) { + /* Make sure throttling gets enabled and set shutdown limit */ + if (!tegra_is_throttling()) { + tegra_throttling_enable(true); + lm95245_set_remote_os_limit(lm95245_device, + colibri_t20_shutdown_temp); + } + /* And re-schedule again */ + msleep(100); + queue_work(thermd_alert_workqueue, &thermd_alert_work); + } + + /* Avoid unbalanced enable for IRQ 367 */ + if (thermd_alert_irq_disabled) { + thermd_alert_irq_disabled = 0; + enable_irq(gpio_to_irq(THERMD_ALERT)); + } +} + +static void colibri_t20_thermd_alert_init(void) +{ + gpio_request(THERMD_ALERT, "THERMD_ALERT"); + gpio_direction_input(THERMD_ALERT); + + thermd_alert_workqueue = create_singlethread_workqueue("THERMD_ALERT"); + + INIT_WORK(&thermd_alert_work, thermd_alert_work_func); +} + +static void lm95245_probe_callback(struct device *dev) +{ + lm95245_device = dev; + + lm95245_set_remote_os_limit(lm95245_device, colibri_t20_throttle_temp); + + if (request_irq(gpio_to_irq(THERMD_ALERT), thermd_alert_irq, + IRQF_TRIGGER_LOW, "THERMD_ALERT", NULL)) + pr_err("%s: unable to register THERMD_ALERT interrupt\n", + __func__); +} + +#ifdef CONFIG_DEBUG_FS +static int colibri_t20_thermal_get_throttle_temp(void *data, u64 *val) +{ + *val = (u64)colibri_t20_throttle_temp; + return 0; +} + +static int colibri_t20_thermal_set_throttle_temp(void *data, u64 val) +{ + colibri_t20_throttle_temp = val; + if (!tegra_is_throttling() && lm95245_device) + lm95245_set_remote_os_limit(lm95245_device, + colibri_t20_throttle_temp); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(throttle_fops, + colibri_t20_thermal_get_throttle_temp, + colibri_t20_thermal_set_throttle_temp, + "%llu\n"); + +static int colibri_t20_thermal_get_shutdown_temp(void *data, u64 *val) +{ + *val = (u64)colibri_t20_shutdown_temp; + return 0; +} + +static int colibri_t20_thermal_set_shutdown_temp(void *data, u64 val) +{ + colibri_t20_shutdown_temp = val; + if (tegra_is_throttling() && lm95245_device) + lm95245_set_remote_os_limit(lm95245_device, + colibri_t20_shutdown_temp); + + /* Carefull as we can only actively monitor one temperatur limit and + assumption is throttling is lower than shutdown one. */ + if (colibri_t20_shutdown_temp < colibri_t20_throttle_temp) + colibri_t20_thermal_set_throttle_temp(NULL, + colibri_t20_shutdown_temp); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(shutdown_fops, + colibri_t20_thermal_get_shutdown_temp, + colibri_t20_thermal_set_shutdown_temp, + "%llu\n"); + +static int __init colibri_t20_thermal_debug_init(void) +{ + struct dentry *thermal_debugfs_root; + + thermal_debugfs_root = debugfs_create_dir("thermal", 0); + + if (!debugfs_create_file("throttle", 0644, thermal_debugfs_root, + NULL, &throttle_fops)) + return -ENOMEM; + + if (!debugfs_create_file("shutdown", 0644, thermal_debugfs_root, + NULL, &shutdown_fops)) + return -ENOMEM; + + return 0; +} +late_initcall(colibri_t20_thermal_debug_init); +#endif /* CONFIG_DEBUG_FS */ + +/* UART */ + +static struct platform_device *colibri_t20_uart_devices[] __initdata = { + &tegra_uarta_device, /* Colibri FFUART */ +#ifndef GMI_32BIT + &tegra_uartd_device, /* Colibri BTUART */ +#endif + &tegra_uartb_device, /* Colibri STDUART */ +}; + +static struct uart_clk_parent uart_parent_clk[] = { + [0] = {.name = "pll_p"}, + [1] = {.name = "pll_m"}, + [2] = {.name = "clk_m"}, +}; + +static struct tegra_uart_platform_data colibri_t20_uart_pdata; + +static void __init uart_debug_init(void) +{ + unsigned long rate; + struct clk *c; + + /* UARTA is the debug port. */ + pr_info("Selecting UARTA as the debug console\n"); + colibri_t20_uart_devices[0] = &debug_uarta_device; + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uarta_device.dev.platform_data))->mapbase; + debug_uart_clk = clk_get_sys("serial8250.0", "uarta"); + + /* Clock enable for the debug channel */ + if (!IS_ERR_OR_NULL(debug_uart_clk)) { + rate = ((struct plat_serial8250_port *)( + debug_uarta_device.dev.platform_data))->uartclk; + pr_info("The debug console clock name is %s\n", + debug_uart_clk->name); + c = tegra_get_clock_by_name("pll_p"); + if (IS_ERR_OR_NULL(c)) + pr_err("Not getting the parent clock pll_p\n"); + else + clk_set_parent(debug_uart_clk, c); + + clk_enable(debug_uart_clk); + clk_set_rate(debug_uart_clk, rate); + } else { + pr_err("Not getting the clock %s for debug console\n", + debug_uart_clk->name); + } +} + +static void __init colibri_t20_uart_init(void) +{ + int i; + struct clk *c; + + for (i = 0; i < ARRAY_SIZE(uart_parent_clk); ++i) { + c = tegra_get_clock_by_name(uart_parent_clk[i].name); + if (IS_ERR_OR_NULL(c)) { + pr_err("Not able to get the clock for %s\n", + uart_parent_clk[i].name); + continue; + } + uart_parent_clk[i].parent_clk = c; + uart_parent_clk[i].fixed_clk_rate = clk_get_rate(c); + } + colibri_t20_uart_pdata.parent_clk_list = uart_parent_clk; + colibri_t20_uart_pdata.parent_clk_count = ARRAY_SIZE(uart_parent_clk); + tegra_uarta_device.dev.platform_data = &colibri_t20_uart_pdata; + tegra_uartb_device.dev.platform_data = &colibri_t20_uart_pdata; +#ifndef GMI_32BIT + tegra_uartd_device.dev.platform_data = &colibri_t20_uart_pdata; +#endif + + /* Register low speed only if it is selected */ + if (!is_tegra_debug_uartport_hs()) + uart_debug_init(); + + platform_add_devices(colibri_t20_uart_devices, + ARRAY_SIZE(colibri_t20_uart_devices)); +} + +/* USB */ + +//TODO: overcurrent + +static struct tegra_usb_platform_data tegra_udc_pdata = { + .has_hostpc = false, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = true, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 8, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.dev = { + .charging_supported = false, + .remote_wakeup_supported = false, + .vbus_gpio = -1, + .vbus_pmu_irq = 0, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .has_hostpc = false, + .op_mode = TEGRA_USB_OPMODE_HOST, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = true, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 9, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 8, + }, + .u_data.host = { + .hot_plug = true, + .power_off_on_suspend = false, + .remote_wakeup_supported = false, + .vbus_gpio = -1, + .vbus_reg = NULL, + }, +}; + +static void ulpi_link_platform_open(void) +{ + int reset_gpio = USB3340_RESETB; + + gpio_request(reset_gpio, "ulpi_phy_reset"); + gpio_direction_output(reset_gpio, 0); + msleep(5); + gpio_direction_output(reset_gpio, 1); +} + +static void ulpi_link_platform_post_phy_on(void) +{ + /* enable VBUS */ + gpio_set_value(LAN_V_BUS, 1); + + /* reset */ + gpio_set_value(LAN_RESET, 0); + + udelay(5); + + /* unreset */ + gpio_set_value(LAN_RESET, 1); +} + +static void ulpi_link_platform_pre_phy_off(void) +{ + /* disable VBUS */ + gpio_set_value(LAN_V_BUS, 0); +} + +static struct tegra_usb_phy_platform_ops ulpi_link_plat_ops = { + .open = ulpi_link_platform_open, + .post_phy_on = ulpi_link_platform_post_phy_on, + .pre_phy_off = ulpi_link_platform_pre_phy_off, +}; + +static struct tegra_usb_platform_data tegra_ehci2_ulpi_link_pdata = { + .has_hostpc = false, + .op_mode = TEGRA_USB_OPMODE_HOST, + .ops = &ulpi_link_plat_ops, + .phy_intf = TEGRA_USB_PHY_INTF_ULPI_LINK, + .port_otg = false, + .u_cfg.ulpi = { + .clk = "cdev2", + .clock_out_delay = 1, + .data_trimmer = 4, + .dir_trimmer = 4, + .shadow_clk_delay = 10, + .stpdirnxt_trimmer = 4, + }, + .u_data.host = { + .hot_plug = false, + .power_off_on_suspend = true, + .remote_wakeup_supported = false, + .vbus_gpio = -1, + .vbus_reg = NULL, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = { + .has_hostpc = false, + .op_mode = TEGRA_USB_OPMODE_HOST, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = false, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 9, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 8, + }, + .u_data.host = { + .hot_plug = true, + .power_off_on_suspend = false, + .remote_wakeup_supported = false, +#ifdef MECS_TELLURIUM_XPOD2 + .vbus_gpio = -1, +#else + .vbus_gpio = USBH_PEN, + .vbus_gpio_inverted = 1, +#endif + .vbus_reg = NULL, + }, +}; + +#ifndef CONFIG_USB_TEGRA_OTG +static struct platform_device *tegra_usb_otg_host_register(void) +{ + struct platform_device *pdev; + void *platform_data; + int val; + + pdev = platform_device_alloc(tegra_ehci1_device.name, + tegra_ehci1_device.id); + if (!pdev) + return NULL; + + val = platform_device_add_resources(pdev, tegra_ehci1_device.resource, + tegra_ehci1_device.num_resources); + if (val) + goto error; + + pdev->dev.dma_mask = tegra_ehci1_device.dev.dma_mask; + pdev->dev.coherent_dma_mask = tegra_ehci1_device.dev.coherent_dma_mask; + + platform_data = kmalloc(sizeof(struct tegra_usb_platform_data), + GFP_KERNEL); + if (!platform_data) + goto error; + + memcpy(platform_data, &tegra_ehci1_utmi_pdata, + sizeof(struct tegra_usb_platform_data)); + pdev->dev.platform_data = platform_data; + + val = platform_device_add(pdev); + if (val) + goto error_add; + + return pdev; + +error_add: + kfree(platform_data); +error: + pr_err("%s: failed to add the host controller device\n", __func__); + platform_device_put(pdev); + return NULL; +} + +static void tegra_usb_otg_host_unregister(struct platform_device *pdev) +{ + platform_device_unregister(pdev); +} + +static struct colibri_otg_platform_data colibri_otg_pdata = { + .cable_detect_gpio = USBC_DET, + .host_register = &tegra_usb_otg_host_register, + .host_unregister = &tegra_usb_otg_host_unregister, +}; +#else /* !CONFIG_USB_TEGRA_OTG */ +static struct tegra_usb_otg_data tegra_otg_pdata = { + .ehci_device = &tegra_ehci1_device, + .ehci_pdata = &tegra_ehci1_utmi_pdata, +}; +#endif /* !CONFIG_USB_TEGRA_OTG */ + +#ifndef CONFIG_USB_TEGRA_OTG +struct platform_device colibri_otg_device = { + .name = "colibri-otg", + .id = -1, + .dev = { + .platform_data = &colibri_otg_pdata, + }, +}; +#endif /* !CONFIG_USB_TEGRA_OTG */ + +static void colibri_t20_usb_init(void) +{ + gpio_request(LAN_V_BUS, "LAN_V_BUS"); + gpio_direction_output(LAN_V_BUS, 0); + gpio_export(LAN_V_BUS, false); + + gpio_request(LAN_RESET, "LAN_RESET"); + gpio_direction_output(LAN_RESET, 0); + gpio_export(LAN_RESET, false); + + /* OTG should be the first to be registered + EHCI instance 0: USB1_DP/N -> USBOTG_P/N */ +#ifndef CONFIG_USB_TEGRA_OTG + platform_device_register(&colibri_otg_device); +#else /* !CONFIG_USB_TEGRA_OTG */ + tegra_otg_device.dev.platform_data = &tegra_otg_pdata; + platform_device_register(&tegra_otg_device); +#endif /* !CONFIG_USB_TEGRA_OTG */ + + /* setup the udc platform data */ + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; + platform_device_register(&tegra_udc_device); + + /* EHCI instance 1: ULPI PHY -> ASIX ETH */ + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_ulpi_link_pdata; + platform_device_register(&tegra_ehci2_device); + + /* EHCI instance 2: USB3_DP/N -> USBH1_P/N */ + tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata; + platform_device_register(&tegra_ehci3_device); + +#ifdef MECS_TELLURIUM +//SD card multiplexing: pull GPIO_PT2 and GPIO_PBB2 low +//working even without any modifications + { + int gpio_status; + unsigned int i2c_scl = I2C_SCL; + unsigned int i2c_sda = I2C_SDA; + unsigned int tellurium_usb_hub_reset = MECS_USB_HUB_RESET; + + printk("MECS Tellurium USB Hub Initialisation\n"); + + /* configure USB hub reset line as output and pull low into + reset */ + gpio_status = gpio_request(tellurium_usb_hub_reset, + "USB_HUB_RESET"); + if (gpio_status < 0) + pr_warning("USB_HUB_RESET request GPIO FAILED\n"); + gpio_status = gpio_direction_output(tellurium_usb_hub_reset, + 0); + if (gpio_status < 0) + pr_warning("USB_HUB_RESET request GPIO DIRECTION " + "FAILED\n"); + + /* configure I2C pins as outputs and pull low */ + gpio_status = gpio_direction_output(i2c_scl, 0); + if (gpio_status < 0) + pr_warning("I2C_SCL request GPIO DIRECTION FAILED\n"); + gpio_status = gpio_direction_output(i2c_sda, 0); + if (gpio_status < 0) + pr_warning("I2C_SDA request GPIO DIRECTION FAILED\n"); + + /* pull USB hub out of reset */ + gpio_set_value(tellurium_usb_hub_reset, 1); + + /* release I2C pins again */ + tegra_gpio_disable(i2c_scl); + tegra_gpio_disable(i2c_sda); + } +#endif /* MECS_TELLURIUM */ +} + +/* W1, aka OWR, aka OneWire */ + +#ifdef CONFIG_W1_MASTER_TEGRA +struct tegra_w1_timings colibri_t20_w1_timings = { + .tsu = 1, + .trelease = 0xf, + .trdv = 0xf, + .tlow0 = 0x3c, + .tlow1 = 1, + .tslot = 0x77, + + .tpdl = 0x78, + .tpdh = 0x1e, + .trstl = 0x1df, + .trsth = 0x1df, + .rdsclk = 0x7, + .psclk = 0x50, +}; + +struct tegra_w1_platform_data colibri_t20_w1_platform_data = { + .clk_id = "tegra_w1", + .timings = &colibri_t20_w1_timings, +}; +#endif /* CONFIG_W1_MASTER_TEGRA */ + +static struct platform_device *colibri_t20_devices[] __initdata = { +#ifdef CONFIG_RTC_DRV_TEGRA + &tegra_rtc_device, +#endif + &tegra_nand_device, + + &tegra_pmu_device, + &tegra_gart_device, + &tegra_aes_device, +#ifdef CONFIG_KEYBOARD_GPIO + &colibri_t20_keys_device, +#endif + &tegra_wdt_device, + &tegra_avp_device, +#ifdef CONFIG_TEGRA_CAMERA + &tegra_camera, +#endif + &tegra_ac97_device, + &tegra_spdif_device, + &tegra_das_device, + &spdif_dit_device, +//bluetooth + &tegra_pcm_device, + &colibri_t20_audio_device, + &tegra_spi_device4, +#ifdef MECS_TELLURIUM_XPOD2 + &xpod2_spi_device, +#endif + &tegra_led_pwm_device, + &tegra_pwfm1_device, +#ifndef MECS_TELLURIUM + &tegra_pwfm2_device, +#else + &tegra_pwfm0_device, +#endif + &tegra_pwfm3_device, +#ifdef CONFIG_W1_MASTER_TEGRA + &tegra_w1_device, +#endif +}; + +static void __init colibri_t20_init(void) +{ + tegra_clk_init_from_table(colibri_t20_clk_init_table); + colibri_t20_pinmux_init(); +#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE) + writel(TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG); + writel(TEGRA_SNOR_CONFIG_GO | TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG); + colibri_can_resource[1].start = gpio_to_irq(TEGRA_GPIO_PA0); + colibri_can_resource[1].end = gpio_to_irq(TEGRA_GPIO_PA0); + platform_device_register(&colibri_can_device); +#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */ + colibri_t20_thermd_alert_init(); + colibri_t20_i2c_init(); + colibri_t20_uart_init(); +// + tegra_ac97_device.dev.platform_data = &colibri_t20_wm97xx_pdata; +// +#ifdef CONFIG_W1_MASTER_TEGRA + tegra_w1_device.dev.platform_data = &colibri_t20_w1_platform_data; +#endif + platform_add_devices(colibri_t20_devices, + ARRAY_SIZE(colibri_t20_devices)); + tegra_ram_console_debug_init(); +#ifndef GMI_32BIT + colibri_t20_sdhci_init(); +#endif + colibri_t20_regulator_init(); + +// tegra_das_device.dev.platform_data = &tegra_das_pdata; +// tegra_ac97_device.dev.platform_data = &tegra_audio_pdata; +// tegra_spdif_input_device.name = "spdif"; +// tegra_spdif_input_device.dev.platform_data = &tegra_spdif_audio_pdata; + + colibri_t20_usb_init(); + colibri_t20_panel_init(); +//sensors + + /* Note: V1.1c modules require proper BCT setting 666 rather than + 721.5 MHz EMC clock */ + colibri_t20_emc_init(); + + colibri_t20_gpio_init(); + colibri_t20_register_spidev(); + colibri_t20_mcp2515_can_init(); + +#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE) + t20_get_tegra_vi01_device()->dev.platform_data = &tegra_camera_platform_data; +#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE) + platform_device_register(&soc_camera_max9526); +#endif +#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE) + platform_device_register(&soc_camera_adv7180); +#endif + +#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */ + + tegra_release_bootloader_fb(); +} + +int __init tegra_colibri_t20_protected_aperture_init(void) +{ + if (!machine_is_colibri_t20()) + return 0; + + tegra_protected_aperture_init(tegra_grhost_aperture); + return 0; +} +late_initcall(tegra_colibri_t20_protected_aperture_init); + +void __init colibri_t20_reserve(void) +{ + if (memblock_reserve(0x0, 4096) < 0) + pr_warn("Cannot reserve first 4K of memory for safety\n"); + + /* we specify zero for special handling due to already reserved + fbmem/nvmem (U-Boot 2011.06 compatibility from our V1.x images) */ + tegra_reserve(0, SZ_8M + SZ_1M, SZ_16M); + tegra_ram_console_debug_reserve(SZ_1M); +} + +static const char *colibri_t20_dt_board_compat[] = { + "toradex,colibri_t20", + NULL +}; + +#ifdef CONFIG_ANDROID +MACHINE_START(COLIBRI_T20, "ventana") +#else +MACHINE_START(COLIBRI_T20, "Toradex Colibri T20") +#endif + .boot_params = 0x00000100, + .dt_compat = colibri_t20_dt_board_compat, + .init_early = tegra_init_early, + .init_irq = tegra_init_irq, + .init_machine = colibri_t20_init, + .map_io = tegra_map_common_io, + .reserve = colibri_t20_reserve, + .timer = &tegra_timer, +MACHINE_END diff --git a/arch/arm/mach-tegra/board-colibri_t20.h b/arch/arm/mach-tegra/board-colibri_t20.h new file mode 100644 index 000000000000..020670d424fd --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t20.h @@ -0,0 +1,88 @@ +/* + * arch/arm/mach-tegra/board-colibri_t20.h + * + * Copyright (C) 2011 Toradex, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MACH_TEGRA_BOARD_COLIBRI_T20_H +#define _MACH_TEGRA_BOARD_COLIBRI_T20_H + +/* Uncomment for camera interface support on Colibri Evaluation carrier + board */ +#if defined(CONFIG_TEGRA_CAMERA) || defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE) +#define COLIBRI_T20_VI +#endif + +/* Uncomment to activate 32-bit GMI address/databus */ +//#define GMI_32BIT + +/* GPIO */ + +#define FF_DCD TEGRA_GPIO_PC6 /* SODIMM 31 */ +#define FF_DSR TEGRA_GPIO_PC1 /* SODIMM 29 */ + +#define I2C_SCL TEGRA_GPIO_PC4 /* SODIMM 196 */ +#define I2C_SDA TEGRA_GPIO_PC5 /* SODIMM 194 */ + +#define LAN_EXT_WAKEUP TEGRA GPIO_PV5 +#define LAN_PME TEGRA_GPIO_PV6 +#define LAN_RESET TEGRA_GPIO_PV4 +#define LAN_V_BUS TEGRA_GPIO_PBB1 + +#define MECS_USB_HUB_RESET TEGRA_GPIO_PBB3 /* SODIMM 127 */ + +#define MMC_CD TEGRA_GPIO_PC7 /* SODIMM 43 */ + +#define NAND_WP_N TEGRA_GPIO_PS0 + +#define PWR_I2C_SCL TEGRA_GPIO_PZ6 +#define PWR_I2C_SDA TEGRA_GPIO_PZ7 + +#define THERMD_ALERT TEGRA_GPIO_PV7 + +#define TOUCH_PEN_INT TEGRA_GPIO_PV2 + +#define USB3340_RESETB TEGRA_GPIO_PV1 +//conflicts with MECS Tellurium xPOD2 SSPTXD2 +#define USBC_DET TEGRA_GPIO_PK5 /* SODIMM 137 */ +#define USBH_OC TEGRA_GPIO_PW3 /* SODIMM 131 */ +#define USBH_PEN TEGRA_GPIO_PW2 /* SODIMM 129 */ + +/* Use SODIMM pin 73 as DAC power save on Iris carrier board */ +#define IRIS + +/* Uncomment for back light and USB hub support on MECS Tellurium carrier + board */ +//#define MECS_TELLURIUM + +/* Uncomment to use the xPOD2 which due to its Colibri T20 incompatible wiring + uses GPIO bit banging SPI driver rather than a hardware SPI controller */ +//#define MECS_TELLURIUM_XPOD2 + +/* Uncomment for 8-bit SDHCI on HSMMC controller (requires custom carrier + board) */ +//#define SDHCI_8BIT + +/* TPS6586X gpios */ +#define TPS6586X_GPIO_BASE TEGRA_NR_GPIOS + +/* Interrupt numbers from external peripherals */ +#define TPS6586X_INT_BASE TEGRA_NR_IRQS +#define TPS6586X_INT_END (TPS6586X_INT_BASE + 32) + +int colibri_t20_emc_init(void); +int colibri_t20_panel_init(void); +int colibri_t20_pinmux_init(void); +int colibri_t20_regulator_init(void); + +#endif diff --git a/arch/arm/mach-tegra/board-colibri_t30-memory.c b/arch/arm/mach-tegra/board-colibri_t30-memory.c new file mode 100644 index 000000000000..22575b48ba0c --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t30-memory.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2012 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/kernel.h> +#include <linux/init.h> + +#include "board.h" +#include "board-colibri_t30.h" +#include "tegra3_emc.h" +#include "fuse.h" + +static const struct tegra_emc_table colibri_t30_emc_tables_nt5cc256m16cp[] = { + { + 0x32, /* Rev 3.2 */ + 400000, /* SDRAM frequency */ + { + 0x00000012, /* EMC_RC */ + 0x0000008a, /* EMC_RFC */ + 0x0000000c, /* EMC_RAS */ + 0x00000004, /* EMC_RP */ + 0x00000003, /* EMC_R2W */ + 0x00000008, /* EMC_W2R */ + 0x00000002, /* EMC_R2P */ + 0x0000000a, /* EMC_W2P */ + 0x00000004, /* EMC_RD_RCD */ + 0x00000004, /* EMC_WR_RCD */ + 0x00000002, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000004, /* EMC_WDV */ + 0x00000006, /* EMC_QUSE */ + 0x00000004, /* EMC_QRST */ + 0x00000009, /* EMC_QSAFE */ + 0x0000000c, /* EMC_RDV */ + 0x00000bf5, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x000002fd, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000001, /* EMC_PDEX2WR */ + 0x00000008, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x00000008, /* EMC_AR2PDEN */ + 0x0000000f, /* EMC_RW2PDEN */ + 0x00000090, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000004, /* EMC_TCKE */ + 0x00000010, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000004, /* EMC_TCLKSTABLE */ + 0x00000005, /* EMC_TCLKSTOP */ + 0x00000c35, /* EMC_TREFBW */ + 0x00000000, /* EMC_QUSE_EXTRA */ + 0x00000004, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00007088, /* EMC_FBIO_CFG5 */ + 0x00360084, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x0000c002, /* EMC_DLL_XFORM_DQS0 */ + 0x00014002, /* EMC_DLL_XFORM_DQS1 */ + 0x0000c002, /* EMC_DLL_XFORM_DQS2 */ + 0x00014002, /* EMC_DLL_XFORM_DQS3 */ + 0x00014000, /* EMC_DLL_XFORM_DQS4 */ + 0x00014000, /* EMC_DLL_XFORM_DQS5 */ + 0x00014000, /* EMC_DLL_XFORM_DQS6 */ + 0x00014000, /* EMC_DLL_XFORM_DQS7 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00018000, /* EMC_DLL_XFORM_DQ0 */ + 0x00018000, /* EMC_DLL_XFORM_DQ1 */ + 0x00018000, /* EMC_DLL_XFORM_DQ2 */ + 0x00018000, /* EMC_DLL_XFORM_DQ3 */ + 0x000002a0, /* EMC_XM2CMDPADCTRL */ + 0x0a00013d, /* EMC_XM2DQSPADCTRL2 */ + 0x00000000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f508, /* EMC_XM2COMPPADCTRL */ + 0x05057404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x08000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x0134000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x800018d1, /* EMC_DYN_SELF_REF_CONTROL */ + 0x00000006, /* MC_EMEM_ARB_CFG */ + 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000009, /* MC_EMEM_ARB_TIMING_RC */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000007, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ + 0x06030202, /* MC_EMEM_ARB_DA_TURNS */ + 0x000d0709, /* MC_EMEM_ARB_DA_COVERS */ + 0x7086120a, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xe8000000, /* EMC_FBIO_SPARE */ + 0xff00ff88, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000000, /* EMC_CFG.PERIODIC_QRST */ + 0x80000521, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200000, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, + { + 0x32, /* Rev 3.2 */ + 800000, /* SDRAM frequency */ + { + 0x00000025, /* EMC_RC */ + 0x00000116, /* EMC_RFC */ + 0x0000001a, /* EMC_RAS */ + 0x00000009, /* EMC_RP */ + 0x00000005, /* EMC_R2W */ + 0x0000000d, /* EMC_W2R */ + 0x00000004, /* EMC_R2P */ + 0x00000013, /* EMC_W2P */ + 0x00000009, /* EMC_RD_RCD */ + 0x00000009, /* EMC_WR_RCD */ + 0x00000006, /* EMC_RRD */ + 0x00000001, /* EMC_REXT */ + 0x00000000, /* EMC_WEXT */ + 0x00000007, /* EMC_WDV */ + 0x0000000a, /* EMC_QUSE */ + 0x00000009, /* EMC_QRST */ + 0x0000000b, /* EMC_QSAFE */ + 0x00000011, /* EMC_RDV */ + 0x0000182a, /* EMC_REFRESH */ + 0x00000000, /* EMC_BURST_REFRESH_NUM */ + 0x0000060a, /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000003, /* EMC_PDEX2WR */ + 0x00000012, /* EMC_PDEX2RD */ + 0x00000001, /* EMC_PCHG2PDEN */ + 0x00000000, /* EMC_ACT2PDEN */ + 0x0000000f, /* EMC_AR2PDEN */ + 0x00000018, /* EMC_RW2PDEN */ + 0x00000120, /* EMC_TXSR */ + 0x00000200, /* EMC_TXSRDLL */ + 0x00000005, /* EMC_TCKE */ + 0x00000020, /* EMC_TFAW */ + 0x00000000, /* EMC_TRPAB */ + 0x00000007, /* EMC_TCLKSTABLE */ + 0x00000008, /* EMC_TCLKSTOP */ + 0x0000186a, /* EMC_TREFBW */ + 0x0000000b, /* EMC_QUSE_EXTRA */ + 0x00000006, /* EMC_FBIO_CFG6 */ + 0x00000000, /* EMC_ODT_WRITE */ + 0x00000000, /* EMC_ODT_READ */ + 0x00005088, /* EMC_FBIO_CFG5 */ + 0xf01a0191, /* EMC_CFG_DIG_DLL */ + 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ + 0x007fc00c, /* EMC_DLL_XFORM_DQS0 */ + 0x0000400c, /* EMC_DLL_XFORM_DQS1 */ + 0x007f800c, /* EMC_DLL_XFORM_DQS2 */ + 0x0000400c, /* EMC_DLL_XFORM_DQS3 */ + 0x0000000c, /* EMC_DLL_XFORM_DQS4 */ + 0x0000000c, /* EMC_DLL_XFORM_DQS5 */ + 0x0000000c, /* EMC_DLL_XFORM_DQS6 */ + 0x0000000c, /* EMC_DLL_XFORM_DQS7 */ + 0x00018000, /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000, /* EMC_DLL_XFORM_QUSE7 */ + 0x00000002, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000002, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000002, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000002, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000002, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000002, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000002, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000002, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00000008, /* EMC_DLL_XFORM_DQ0 */ + 0x00000008, /* EMC_DLL_XFORM_DQ1 */ + 0x00000008, /* EMC_DLL_XFORM_DQ2 */ + 0x00000008, /* EMC_DLL_XFORM_DQ3 */ + 0x000602a0, /* EMC_XM2CMDPADCTRL */ + 0x0a00013d, /* EMC_XM2DQSPADCTRL2 */ + 0x22220000, /* EMC_XM2DQPADCTRL2 */ + 0x77fff884, /* EMC_XM2CLKPADCTRL */ + 0x01f1f501, /* EMC_XM2COMPPADCTRL */ + 0x07077404, /* EMC_XM2VTTGENPADCTRL */ + 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */ + 0x080001e8, /* EMC_XM2QUSEPADCTRL */ + 0x08000021, /* EMC_XM2DQSPADCTRL3 */ + 0x00000802, /* EMC_CTT_TERM_CTRL */ + 0x00020000, /* EMC_ZCAL_INTERVAL */ + 0x00000100, /* EMC_ZCAL_WAIT_CNT */ + 0x00a8000c, /* EMC_MRS_WAIT_CNT */ + 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */ + 0x00000000, /* EMC_CTT */ + 0x00000000, /* EMC_CTT_DURATION */ + 0x8000309f, /* EMC_DYN_SELF_REF_CONTROL */ + 0x0000000c, /* MC_EMEM_ARB_CFG */ + 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000005, /* MC_EMEM_ARB_TIMING_RP */ + 0x00000013, /* MC_EMEM_ARB_TIMING_RC */ + 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */ + 0x0000000f, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */ + 0x08040202, /* MC_EMEM_ARB_DA_TURNS */ + 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */ + 0x712c2414, /* MC_EMEM_ARB_MISC0 */ + 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ + 0xf8000000, /* EMC_FBIO_SPARE */ + 0xff00ff49, /* EMC_CFG_RSV */ + }, + 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */ + 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ + 0x00000001, /* EMC_CFG.PERIODIC_QRST */ + 0x80000d71, /* Mode Register 0 */ + 0x80100002, /* Mode Register 1 */ + 0x80200018, /* Mode Register 2 */ + 0x00000000, /* EMC_CFG.DYN_SELF_REF */ + }, +}; + +int colibri_t30_emc_init(void) +{ + tegra_init_emc(colibri_t30_emc_tables_nt5cc256m16cp, + ARRAY_SIZE(colibri_t30_emc_tables_nt5cc256m16cp)); + + return 0; +} diff --git a/arch/arm/mach-tegra/board-colibri_t30-panel.c b/arch/arm/mach-tegra/board-colibri_t30-panel.c new file mode 100644 index 000000000000..14c711039f41 --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t30-panel.c @@ -0,0 +1,529 @@ +/* + * arch/arm/mach-tegra/board-colibri_t30-panel.c + * + * Copyright (c) 2012, Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <asm/atomic.h> +#include <asm/mach-types.h> + +#include <linux/delay.h> +#include <linux/earlysuspend.h> +#include <linux/gpio.h> +#include <linux/ion.h> +#include <linux/nvhost.h> +#include <linux/nvmap.h> +#include <linux/platform_device.h> +#include <linux/pwm_backlight.h> +#include <linux/regulator/consumer.h> +#include <linux/resource.h> +#include <linux/tegra_ion.h> + +#include <mach/dc.h> +#include <mach/fb.h> +#include <mach/iomap.h> +#include <mach/irqs.h> +#include <mach/smmu.h> + +#include "board.h" +#include "board-colibri_t30.h" +#include "devices.h" +#include "gpio-names.h" +#include "tegra3_host1x_devices.h" + +#ifndef COLIBRI_T30_VI +#define colibri_t30_bl_enb TEGRA_GPIO_PV2 /* BL_ON */ +#endif +#define colibri_t30_hdmi_hpd TEGRA_GPIO_PN7 /* HDMI_INT_N */ + +static struct regulator *colibri_t30_hdmi_pll = NULL; +static struct regulator *colibri_t30_hdmi_reg = NULL; + +#ifndef COLIBRI_T30_VI +static int colibri_t30_backlight_init(struct device *dev) { + int ret; + + ret = gpio_request(colibri_t30_bl_enb, "BL_ON"); + if (ret < 0) + return ret; + + ret = gpio_direction_output(colibri_t30_bl_enb, 1); + if (ret < 0) + gpio_free(colibri_t30_bl_enb); + + return ret; +}; + +static void colibri_t30_backlight_exit(struct device *dev) { + gpio_set_value(colibri_t30_bl_enb, 0); + gpio_free(colibri_t30_bl_enb); +} + +static int colibri_t30_backlight_notify(struct device *dev, int brightness) +{ + struct platform_pwm_backlight_data *pdata = dev->platform_data; + + gpio_set_value(colibri_t30_bl_enb, !!brightness); + + /* Unified TFT interface displays (e.g. EDT ET070080DH6) LEDCTRL pin + with inverted behaviour (e.g. 0V brightest vs. 3.3V darkest) + Note: brightness polarity display model specific */ + if (brightness) return pdata->max_brightness - brightness; + else return brightness; +} + +static int colibri_t30_disp1_check_fb(struct device *dev, struct fb_info *info); + +static struct platform_pwm_backlight_data colibri_t30_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 127, + .pwm_period_ns = 1000000, /* 1 kHz */ + .init = colibri_t30_backlight_init, + .exit = colibri_t30_backlight_exit, + .notify = colibri_t30_backlight_notify, + /* Only toggle backlight on fb blank notifications for disp1 */ + .check_fb = colibri_t30_disp1_check_fb, +}; + +static struct platform_device colibri_t30_backlight_device = { + .name = "pwm-backlight", + .id = -1, + .dev = { + .platform_data = &colibri_t30_backlight_data, + }, +}; +#endif /* !COLIBRI_T30_VI */ + +static int colibri_t30_panel_enable(void) +{ + return 0; +} + +static int colibri_t30_panel_disable(void) +{ + return 0; +} + +#ifdef CONFIG_TEGRA_DC + +static int colibri_t30_hdmi_enable(void) +{ + int ret; + if (!colibri_t30_hdmi_reg) { + colibri_t30_hdmi_reg = regulator_get(NULL, "avdd_hdmi"); + if (IS_ERR_OR_NULL(colibri_t30_hdmi_reg)) { + pr_err("hdmi: couldn't get regulator avdd_hdmi\n"); + colibri_t30_hdmi_reg = NULL; + return PTR_ERR(colibri_t30_hdmi_reg); + } + } + ret = regulator_enable(colibri_t30_hdmi_reg); + if (ret < 0) { + pr_err("hdmi: couldn't enable regulator avdd_hdmi\n"); + return ret; + } + if (!colibri_t30_hdmi_pll) { + colibri_t30_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll"); + if (IS_ERR_OR_NULL(colibri_t30_hdmi_pll)) { + pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n"); + colibri_t30_hdmi_pll = NULL; + regulator_put(colibri_t30_hdmi_reg); + colibri_t30_hdmi_reg = NULL; + return PTR_ERR(colibri_t30_hdmi_pll); + } + } + ret = regulator_enable(colibri_t30_hdmi_pll); + if (ret < 0) { + pr_err("hdmi: couldn't enable regulator avdd_hdmi_pll\n"); + return ret; + } + return 0; +} + +static int colibri_t30_hdmi_disable(void) +{ + regulator_disable(colibri_t30_hdmi_reg); + regulator_put(colibri_t30_hdmi_reg); + colibri_t30_hdmi_reg = NULL; + + regulator_disable(colibri_t30_hdmi_pll); + regulator_put(colibri_t30_hdmi_pll); + colibri_t30_hdmi_pll = NULL; + return 0; +} +static struct resource colibri_t30_disp1_resources[] = { + { + .name = "irq", + .start = INT_DISPLAY_GENERAL, + .end = INT_DISPLAY_GENERAL, + .flags = IORESOURCE_IRQ, + }, + { + .name = "regs", + .start = TEGRA_DISPLAY_BASE, + .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1, + .flags = IORESOURCE_MEM, + }, + { + .name = "fbmem", + .start = 0, /* Filled in by colibri_t30_panel_init() */ + .end = 0, /* Filled in by colibri_t30_panel_init() */ + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource colibri_t30_disp2_resources[] = { + { + .name = "irq", + .start = INT_DISPLAY_B_GENERAL, + .end = INT_DISPLAY_B_GENERAL, + .flags = IORESOURCE_IRQ, + }, + { + .name = "regs", + .start = TEGRA_DISPLAY2_BASE, + .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "fbmem", + .flags = IORESOURCE_MEM, + .start = 0, + .end = 0, + }, + { + .name = "hdmi_regs", + .start = TEGRA_HDMI_BASE, + .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct tegra_fb_data colibri_t30_fb_data = { + .win = 0, + .flags = TEGRA_FB_FLIP_ON_PROBE, +}; + +static struct tegra_fb_data colibri_t30_hdmi_fb_data = { + .win = 0, + .flags = TEGRA_FB_FLIP_ON_PROBE, +}; + +static struct tegra_dc_out_pin colibri_t30_dc_out_pins[] = { + { + .name = TEGRA_DC_OUT_PIN_H_SYNC, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, + { + .name = TEGRA_DC_OUT_PIN_V_SYNC, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, + { + .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, +}; + +static struct tegra_dc_out colibri_t30_disp1_out = { + .type = TEGRA_DC_OUT_RGB, + .parent_clk = "pll_d_out0", + .parent_clk_backup = "pll_d2_out0", + + .align = TEGRA_DC_ALIGN_MSB, + .order = TEGRA_DC_ORDER_RED_BLUE, + .depth = 18, + .dither = TEGRA_DC_ORDERED_DITHER, + + /* Use 32-bit depth for android builds */ +#ifdef CONFIG_ANDROID + .default_mode = "640x480-32@60", +#else /* CONFIG_ANDROID */ + .default_mode = "640x480-16@60", +#endif /* CONFIG_ANDROID */ + + .out_pins = colibri_t30_dc_out_pins, + .n_out_pins = ARRAY_SIZE(colibri_t30_dc_out_pins), + + .enable = colibri_t30_panel_enable, + .disable = colibri_t30_panel_disable, +}; + +static struct tegra_dc_out colibri_t30_disp2_out = { + .type = TEGRA_DC_OUT_HDMI, + .flags = TEGRA_DC_OUT_HOTPLUG_HIGH, + .parent_clk = "pll_d2_out0", + + .dcc_bus = 3, + .hotplug_gpio = colibri_t30_hdmi_hpd, + + .max_pixclock = KHZ2PICOS(148500), + + /* Use 32-bit depth and Full HD for android builds */ +#ifdef CONFIG_ANDROID + .default_mode = "1920x1080-32@60", +#else /* CONFIG_ANDROID */ + .default_mode = "640x480-16@60", +#endif /* CONFIG_ANDROID */ + + .align = TEGRA_DC_ALIGN_MSB, + .order = TEGRA_DC_ORDER_RED_BLUE, + + .enable = colibri_t30_hdmi_enable, + .disable = colibri_t30_hdmi_disable, +}; + +static struct tegra_dc_platform_data colibri_t30_disp1_pdata = { + .flags = TEGRA_DC_FLAG_ENABLED, + .default_out = &colibri_t30_disp1_out, + .emc_clk_rate = 300000000, + .fb = &colibri_t30_fb_data, +}; + +static struct tegra_dc_platform_data colibri_t30_disp2_pdata = { + .flags = TEGRA_DC_FLAG_ENABLED, + .default_out = &colibri_t30_disp2_out, + .fb = &colibri_t30_hdmi_fb_data, + .emc_clk_rate = 300000000, +}; + +static struct nvhost_device colibri_t30_disp1_device = { + .name = "tegradc", + .id = 0, + .resource = colibri_t30_disp1_resources, + .num_resources = ARRAY_SIZE(colibri_t30_disp1_resources), + .dev = { + .platform_data = &colibri_t30_disp1_pdata, + }, +}; + +#ifndef COLIBRI_T30_VI +static int colibri_t30_disp1_check_fb(struct device *dev, struct fb_info *info) +{ + return info->device == &colibri_t30_disp1_device.dev; +} +#endif /* !COLIBRI_T30_VI */ + +static struct nvhost_device colibri_t30_disp2_device = { + .name = "tegradc", + .id = 1, + .resource = colibri_t30_disp2_resources, + .num_resources = ARRAY_SIZE(colibri_t30_disp2_resources), + .dev = { + .platform_data = &colibri_t30_disp2_pdata, + }, +}; +#else /* CONFIG_TEGRA_DC */ +static int colibri_t30_disp1_check_fb(struct device *dev, struct fb_info *info) +{ + return 0; +} +#endif /* CONFIG_TEGRA_DC */ + +#if defined(CONFIG_TEGRA_NVMAP) +static struct nvmap_platform_carveout colibri_t30_carveouts[] = { + [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT, + [1] = { + .name = "generic-0", + .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC, + .base = 0, /* Filled in by colibri_t30_panel_init() */ + .size = 0, /* Filled in by colibri_t30_panel_init() */ + .buddy_size = SZ_32K, + }, +}; + +static struct nvmap_platform_data colibri_t30_nvmap_data = { + .carveouts = colibri_t30_carveouts, + .nr_carveouts = ARRAY_SIZE(colibri_t30_carveouts), +}; + +static struct platform_device colibri_t30_nvmap_device = { + .name = "tegra-nvmap", + .id = -1, + .dev = { + .platform_data = &colibri_t30_nvmap_data, + }, +}; +#endif /* CONFIG_TEGRA_NVMAP */ + +#if defined(CONFIG_ION_TEGRA) +static struct platform_device tegra_iommu_device = { + .name = "tegra_iommu_device", + .id = -1, + .dev = { + .platform_data = (void *)((1 << HWGRP_COUNT) - 1), + }, +}; + +static struct ion_platform_data tegra_ion_data = { + .nr = 4, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = TEGRA_ION_HEAP_CARVEOUT, + .name = "carveout", + .base = 0, + .size = 0, + }, + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = TEGRA_ION_HEAP_IRAM, + .name = "iram", + .base = TEGRA_IRAM_BASE + TEGRA_RESET_HANDLER_SIZE, + .size = TEGRA_IRAM_SIZE - TEGRA_RESET_HANDLER_SIZE, + }, + { + .type = ION_HEAP_TYPE_CARVEOUT, + .id = TEGRA_ION_HEAP_VPR, + .name = "vpr", + .base = 0, + .size = 0, + }, + { + .type = ION_HEAP_TYPE_IOMMU, + .id = TEGRA_ION_HEAP_IOMMU, + .name = "iommu", + .base = TEGRA_SMMU_BASE, + .size = TEGRA_SMMU_SIZE, + .priv = &tegra_iommu_device.dev, + }, + }, +}; + +static struct platform_device tegra_ion_device = { + .name = "ion-tegra", + .id = -1, + .dev = { + .platform_data = &tegra_ion_data, + }, +}; +#endif /* CONFIG_ION_TEGRA */ + +static struct platform_device *colibri_t30_gfx_devices[] __initdata = { +#if defined(CONFIG_TEGRA_NVMAP) + &colibri_t30_nvmap_device, +#endif +#if defined(CONFIG_ION_TEGRA) + &tegra_ion_device, +#endif +#ifndef COLIBRI_T30_VI + &tegra_pwfm0_device, + &colibri_t30_backlight_device, +#endif /* !COLIBRI_T30_VI */ +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +/* put early_suspend/late_resume handlers here for the display in order + * to keep the code out of the display driver, keeping it closer to upstream + */ +struct early_suspend colibri_t30_panel_early_suspender; + +static void colibri_t30_panel_early_suspend(struct early_suspend *h) +{ + /* power down LCD, add use a black screen for HDMI */ + if (num_registered_fb > 0) + fb_blank(registered_fb[0], FB_BLANK_POWERDOWN); + if (num_registered_fb > 1) + fb_blank(registered_fb[1], FB_BLANK_NORMAL); +} + +static void colibri_t30_panel_late_resume(struct early_suspend *h) +{ + unsigned i; + for (i = 0; i < num_registered_fb; i++) + fb_blank(registered_fb[i], FB_BLANK_UNBLANK); +} +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +int __init colibri_t30_panel_init(void) +{ + int err = 0; + struct resource *res; + void __iomem *to_io; + + /* enable hdmi hotplug gpio for hotplug detection */ + gpio_request(colibri_t30_hdmi_hpd, "hdmi_hpd"); + gpio_direction_input(colibri_t30_hdmi_hpd); + +#ifdef CONFIG_HAS_EARLYSUSPEND + colibri_t30_panel_early_suspender.suspend = colibri_t30_panel_early_suspend; + colibri_t30_panel_early_suspender.resume = colibri_t30_panel_late_resume; + colibri_t30_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + register_early_suspend(&colibri_t30_panel_early_suspender); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +#ifdef CONFIG_TEGRA_NVMAP + colibri_t30_carveouts[1].base = tegra_carveout_start; + colibri_t30_carveouts[1].size = tegra_carveout_size; +#endif /* CONFIG_TEGRA_NVMAP */ + +#ifdef CONFIG_ION_TEGRA + tegra_ion_data.heaps[0].base = tegra_carveout_start; + tegra_ion_data.heaps[0].size = tegra_carveout_size; +#endif /* CONFIG_ION_TEGRA */ + +#ifdef CONFIG_TEGRA_GRHOST + err = tegra3_register_host1x_devices(); + if (err) + return err; +#endif /* CONFIG_TEGRA_GRHOST */ + + err = platform_add_devices(colibri_t30_gfx_devices, + ARRAY_SIZE(colibri_t30_gfx_devices)); + +#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) + res = nvhost_get_resource_byname(&colibri_t30_disp1_device, + IORESOURCE_MEM, "fbmem"); + res->start = tegra_fb_start; + res->end = tegra_fb_start + tegra_fb_size - 1; + + res = nvhost_get_resource_byname(&colibri_t30_disp2_device, + IORESOURCE_MEM, "fbmem"); + res->start = tegra_fb2_start; + res->end = tegra_fb2_start + tegra_fb2_size - 1; +#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */ + + /* Make sure LVDS framebuffer is cleared. */ + to_io = ioremap(tegra_fb_start, tegra_fb_size); + if (to_io) { + memset(to_io, 0, tegra_fb_size); + iounmap(to_io); + } else pr_err("%s: Failed to map LVDS framebuffer\n", __func__); + + /* Make sure HDMI framebuffer is cleared. + Note: this seems to fix a tegradc.1 initialisation race in case of + framebuffer console as well. */ + to_io = ioremap(tegra_fb2_start, tegra_fb2_size); + if (to_io) { + memset(to_io, 0, tegra_fb2_size); + iounmap(to_io); + } else pr_err("%s: Failed to map HDMI framebuffer\n", __func__); + +#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC) + if (!err) + err = nvhost_device_register(&colibri_t30_disp1_device); + + if (!err) + err = nvhost_device_register(&colibri_t30_disp2_device); +#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */ + +#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_NVAVP) + if (!err) + err = nvhost_device_register(&nvavp_device); +#endif + return err; +} diff --git a/arch/arm/mach-tegra/board-colibri_t30-pinmux.c b/arch/arm/mach-tegra/board-colibri_t30-pinmux.c new file mode 100644 index 000000000000..f02060c3d535 --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t30-pinmux.c @@ -0,0 +1,658 @@ +/* + * arch/arm/mach-tegra/board-colibri_t30-pinmux.c + * + * Copyright (C) 2012 Toradex, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> + +#include <mach/pinmux.h> + +#include "board-colibri_t30.h" +#include "board.h" +#include "gpio-names.h" + +#define DEFAULT_DRIVE(_name) \ + { \ + .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \ + .hsm = TEGRA_HSM_DISABLE, \ + .schmitt = TEGRA_SCHMITT_ENABLE, \ + .drive = TEGRA_DRIVE_DIV_1, \ + .pull_down = TEGRA_PULL_31, \ + .pull_up = TEGRA_PULL_31, \ + .slew_rising = TEGRA_SLEW_SLOWEST, \ + .slew_falling = TEGRA_SLEW_SLOWEST, \ + } + +/* Setting the drive strength of pins + * hsm: Enable High speed mode (ENABLE/DISABLE) + * Schimit: Enable/disable schimit (ENABLE/DISABLE) + * drive: low power mode (DIV_1, DIV_2, DIV_4, DIV_8) + * pulldn_drive - drive down (falling edge) - Driver Output Pull-Down drive + * strength code. Value from 0 to 31. + * pullup_drive - drive up (rising edge) - Driver Output Pull-Up drive + * strength code. Value from 0 to 31. + * pulldn_slew - Driver Output Pull-Up slew control code - 2bit code + * code 11 is least slewing of signal. code 00 is highest + * slewing of the signal. + * Value - FASTEST, FAST, SLOW, SLOWEST + * pullup_slew - Driver Output Pull-Down slew control code - + * code 11 is least slewing of signal. code 00 is highest + * slewing of the signal. + * Value - FASTEST, FAST, SLOW, SLOWEST + */ +#define SET_DRIVE(_name, _hsm, _schmitt, _drive, _pulldn_drive, _pullup_drive, _pulldn_slew, _pullup_slew) \ + { \ + .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \ + .hsm = TEGRA_HSM_##_hsm, \ + .schmitt = TEGRA_SCHMITT_##_schmitt, \ + .drive = TEGRA_DRIVE_##_drive, \ + .pull_down = TEGRA_PULL_##_pulldn_drive, \ + .pull_up = TEGRA_PULL_##_pullup_drive, \ + .slew_rising = TEGRA_SLEW_##_pulldn_slew, \ + .slew_falling = TEGRA_SLEW_##_pullup_slew, \ + } + +static __initdata struct tegra_drive_pingroup_config colibri_t30_drive_pinmux[] = { + /* DEFAULT_DRIVE(<pin_group>), */ + + /* Audio codec */ + SET_DRIVE(DAP2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + + /* All I2C pins are driven to maximum drive strength */ + + /* GEN1_I2C: I2C_SDA/SCL on SODIMM pin 194/196 (e.g. RTC on carrier board) */ + SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + + /* DDC_CLOCK/DATA on X3 pin 15/16 (e.g. display EDID) */ + SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + + /* PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and + touch screen controller */ + SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST), + + /* SDMMC2 */ + SET_DRIVE(AO2, DISABLE, DISABLE, DIV_1, 46, 42, FAST, FAST), + + /* eMMC on SDMMC4 */ + SET_DRIVE(GMA, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST), + SET_DRIVE(GMB, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST), + SET_DRIVE(GMC, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST), + SET_DRIVE(GMD, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST), +}; + +#define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \ + { \ + .pingroup = TEGRA_PINGROUP_##_pingroup, \ + .func = TEGRA_MUX_##_mux, \ + .pupd = TEGRA_PUPD_##_pupd, \ +/* TRISTATE here means output driver is tri-stated */ \ + .tristate = TEGRA_TRI_##_tri, \ +/* INPUT here means input driver is enabled vs. OUTPUT where it is disabled */ \ + .io = TEGRA_PIN_##_io, \ + .lock = TEGRA_PIN_LOCK_DEFAULT, \ + .od = TEGRA_PIN_OD_DEFAULT, \ + .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \ + } + +#define I2C_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _od) \ + { \ + .pingroup = TEGRA_PINGROUP_##_pingroup, \ + .func = TEGRA_MUX_##_mux, \ + .pupd = TEGRA_PUPD_##_pupd, \ + .tristate = TEGRA_TRI_##_tri, \ + .io = TEGRA_PIN_##_io, \ + .lock = TEGRA_PIN_LOCK_##_lock, \ + .od = TEGRA_PIN_OD_##_od, \ + .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \ + } + +#define VI_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _ioreset) \ + { \ + .pingroup = TEGRA_PINGROUP_##_pingroup, \ + .func = TEGRA_MUX_##_mux, \ + .pupd = TEGRA_PUPD_##_pupd, \ + .tristate = TEGRA_TRI_##_tri, \ + .io = TEGRA_PIN_##_io, \ + .lock = TEGRA_PIN_LOCK_##_lock, \ + .od = TEGRA_PIN_OD_DEFAULT, \ + .ioreset = TEGRA_PIN_IO_RESET_##_ioreset \ + } + +static __initdata struct tegra_pingroup_config colibri_t30_pinmux[] = { +//multiplexed KB_ROW_13 +#ifdef COLIBRI_T30_SDMMC4B + I2C_PINMUX(CAM_I2C_SCL, POPSDMMC4, PULL_UP, NORMAL, INPUT, DEFAULT, DISABLE), +#else + I2C_PINMUX(CAM_I2C_SCL, I2C3, NORMAL, TRISTATE, OUTPUT, DEFAULT, DISABLE), +#endif +//multiplexed KB_ROW_14 +#ifdef COLIBRI_T30_SDMMC4B + I2C_PINMUX(CAM_I2C_SDA, POPSDMMC4, PULL_UP, NORMAL, INPUT, DEFAULT, DISABLE), +#else + I2C_PINMUX(CAM_I2C_SDA, I2C3, NORMAL, TRISTATE, OUTPUT, DEFAULT, DISABLE), +#endif +//multiplexed KB_ROW_10 +#ifdef COLIBRI_T30_SDMMC4B + DEFAULT_PINMUX(CAM_MCLK, POPSDMMC4, NORMAL, NORMAL, INPUT), +#else + DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, NORMAL, TRISTATE, OUTPUT), +#endif + + DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(CLK1_REQ, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(CLK2_OUT, EXTPERIPH2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(CLK2_REQ, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(CLK3_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(CLK3_REQ, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + + DEFAULT_PINMUX(CLK_32K_OUT, RSVD1, NORMAL, TRISTATE, OUTPUT), + + DEFAULT_PINMUX(CRT_HSYNC, CRT, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(CRT_VSYNC, CRT, NORMAL, NORMAL, OUTPUT), + + DEFAULT_PINMUX(DAP1_DIN, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP1_DOUT, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP1_FS, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP1_SCLK, GMI, NORMAL, NORMAL, INPUT), + +//multiplexed LCD_D23 + DEFAULT_PINMUX(DAP2_DIN, GMI, NORMAL, TRISTATE, OUTPUT), +//multiplexed LCD_D22 + DEFAULT_PINMUX(DAP2_DOUT, GMI, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(DAP2_FS, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP2_SCLK, GMI, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT), +// DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, OUTPUT), +// DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(DAP4_DIN, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP4_DOUT, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP4_FS, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(DAP4_SCLK, GMI, NORMAL, NORMAL, INPUT), + + I2C_PINMUX(DDC_SCL, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + I2C_PINMUX(DDC_SDA, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + + I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + I2C_PINMUX(GEN1_I2C_SDA, I2C1, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + + I2C_PINMUX(GEN2_I2C_SCL, RSVD3, PULL_UP, NORMAL, INPUT, DEFAULT, DISABLE), + I2C_PINMUX(GEN2_I2C_SDA, RSVD3, PULL_UP, NORMAL, INPUT, DEFAULT, DISABLE), + + DEFAULT_PINMUX(GMI_A16, UARTD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_A17, UARTD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_A18, UARTD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_A19, UARTD, NORMAL, NORMAL, INPUT), +#ifdef COLIBRI_T30_V10 + DEFAULT_PINMUX(GMI_AD0, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD1, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD2, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD3, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD4, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD5, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD6, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD7, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD8, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD9, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD10, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD11, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD12, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD13, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD14, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD15, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_ADV_N, NAND, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GMI_CLK, NAND, NORMAL, NORMAL, OUTPUT), +#else /* COLIBRI_T30_V10 */ + DEFAULT_PINMUX(GMI_AD0, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD1, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD2, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD3, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD4, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD5, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD6, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD7, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD8, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD9, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD10, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD11, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD12, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD13, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD14, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_AD15, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_ADV_N, GMI, NORMAL, NORMAL, INPUT), +//multiplexed OWR + DEFAULT_PINMUX(GMI_CLK, GMI, NORMAL, TRISTATE, OUTPUT), +#endif /* COLIBRI_T30_V10 */ + DEFAULT_PINMUX(GMI_CS0_N, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_CS1_N, RSVD1, NORMAL, NORMAL, INPUT), +#ifdef COLIBRI_T30_V10 + DEFAULT_PINMUX(GMI_CS2_N, NAND, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GMI_CS3_N, NAND, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GMI_CS4_N, NAND, NORMAL, NORMAL, OUTPUT), +#else /* COLIBRI_T30_V10 */ + DEFAULT_PINMUX(GMI_CS2_N, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_CS3_N, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_CS4_N, GMI, NORMAL, NORMAL, INPUT), +#endif /* COLIBRI_T30_V10 */ + DEFAULT_PINMUX(GMI_CS6_N, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_CS7_N, GMI, NORMAL, NORMAL, INPUT), +#ifdef COLIBRI_T30_V10 + DEFAULT_PINMUX(GMI_DQS, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_IORDY, NAND, NORMAL, NORMAL, OUTPUT), + DEFAULT_PINMUX(GMI_OE_N, NAND, NORMAL, NORMAL, OUTPUT), +#else /* COLIBRI_T30_V10 */ + DEFAULT_PINMUX(GMI_DQS, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ +//multiplexed GMI_WAIT + DEFAULT_PINMUX(GMI_IORDY, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_OE_N, GMI, NORMAL, NORMAL, INPUT), +#endif /* COLIBRI_T30_V10 */ + DEFAULT_PINMUX(GMI_RST_N, GMI, NORMAL, NORMAL, INPUT), +#ifdef COLIBRI_T30_V10 + DEFAULT_PINMUX(GMI_WAIT, NAND, NORMAL, NORMAL, INPUT), +//GPIO C7: eMMC vs. NAND flash detection + DEFAULT_PINMUX(GMI_WP_N, NAND, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_WR_N, NAND, NORMAL, NORMAL, OUTPUT), +#else /* COLIBRI_T30_V10 */ +//multiplexed GMI_IORDY + DEFAULT_PINMUX(GMI_WAIT, GMI, NORMAL, TRISTATE, OUTPUT), +//GPIO PU6: MMC_CD + DEFAULT_PINMUX(GMI_WP_N, RSVD1, NORMAL, NORMAL, INPUT), +//gated, multiplexed LCD_CS1_N or LCD_WR_N + DEFAULT_PINMUX(GMI_WR_N, GMI, NORMAL, NORMAL, INPUT), +#endif /* COLIBRI_T30_V10 */ + +//multiplexed KB_ROW_12 +#ifdef COLIBRI_T30_SDMMC4B + DEFAULT_PINMUX(GPIO_PBB0, POPSDMMC4, PULL_UP, NORMAL, INPUT), +#else + DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, TRISTATE, OUTPUT), +#endif +//multiplexed KB_ROW_15 +#ifdef COLIBRI_T30_SDMMC4B + DEFAULT_PINMUX(GPIO_PBB3, POPSDMMC4, PULL_UP, NORMAL, INPUT), +#else + DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, TRISTATE, OUTPUT), +#endif + DEFAULT_PINMUX(GPIO_PBB4, VGP4, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PBB5, VGP5, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PBB6, VGP6, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PBB7, RSVD1, NORMAL, NORMAL, INPUT), + +//multiplexed KB_ROW_11 +#ifdef COLIBRI_T30_SDMMC4B + DEFAULT_PINMUX(GPIO_PCC1, POPSDMMC4, NORMAL, NORMAL, INPUT), +#else + DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, TRISTATE, OUTPUT), +#endif +#ifdef COLIBRI_T30_SDMMC4B +//when used for SDMMC4: 10k to VDDIO_CAM + DEFAULT_PINMUX(GPIO_PCC2, POPSDMMC4, PULL_UP, NORMAL, INPUT), +#else /* COLIBRI_T30_SDMMC4B */ +//multiplexed VI_D11 +#ifdef COLIBRI_T30_VI + DEFAULT_PINMUX(GPIO_PCC2, RSVD1, NORMAL, TRISTATE, OUTPUT), +#else + DEFAULT_PINMUX(GPIO_PCC2, RSVD1, PULL_UP, NORMAL, INPUT), +#endif +#endif /* COLIBRI_T30_SDMMC4B */ + + DEFAULT_PINMUX(GPIO_PU0, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PU1, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PU2, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PU3, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PU4, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PU5, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PU6, GMI, NORMAL, NORMAL, INPUT), + +//GPIO V0: touch pendown int + DEFAULT_PINMUX(GPIO_PV0, RSVD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PV1, RSVD, NORMAL, NORMAL, INPUT), +#ifdef COLIBRI_T30_VI +//multiplexed VI_D0 + DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, TRISTATE, OUTPUT), +//multiplexed VI_D8 + DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, TRISTATE, OUTPUT), +#else +//GPIO V2: BL_ON + DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, NORMAL, INPUT), +#endif + + DEFAULT_PINMUX(HDMI_CEC, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ +//GPIO N7: HOTPLUG_DETECT + DEFAULT_PINMUX(HDMI_INT, RSVD0, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(JTAG_RTCK, RTCK, NORMAL, NORMAL, OUTPUT), + +//all tristate? + DEFAULT_PINMUX(KB_COL0, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL1, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL2, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL3, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL4, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL5, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL6, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_COL7, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW0, RSVD2, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW1, RSVD2, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW2, RSVD2, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW3, RSVD2, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW4, RSVD3, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW5, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW6, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW7, KBC, NORMAL, TRISTATE, INPUT), + DEFAULT_PINMUX(KB_ROW8, KBC, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW9, KBC, NORMAL, TRISTATE, INPUT), + +//multiplexed SDMMC4.B +#ifdef COLIBRI_T30_SDMMC4B + DEFAULT_PINMUX(KB_ROW10, KBC, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(KB_ROW11, KBC, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(KB_ROW13, KBC, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(KB_ROW14, KBC, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(KB_ROW15, KBC, NORMAL, TRISTATE, OUTPUT), +#else + DEFAULT_PINMUX(KB_ROW10, SDMMC2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW11, SDMMC2, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW12, SDMMC2, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW13, SDMMC2, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW14, SDMMC2, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(KB_ROW15, SDMMC2, PULL_UP, NORMAL, INPUT), +#endif + + DEFAULT_PINMUX(LCD_CS0_N, RSVD, NORMAL, NORMAL, INPUT), +//multiplexed with SDMMC3_DAT5 gated GMI_WR_N + DEFAULT_PINMUX(LCD_CS1_N, RSVD2, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D5, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D6, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D7, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D9, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D10, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D11, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D12, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, INPUT), + +//multiplexed + DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D19, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D20, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D22, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(LCD_DC0, RSVD1, NORMAL, NORMAL, INPUT), +//GPIO D2: THERMD_ALERT_N + DEFAULT_PINMUX(LCD_DC1, RSVD1, NORMAL, NORMAL, INPUT), +//multiplexed LCD_M1 + DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_HSYNC, DISPLAYA, NORMAL, NORMAL, INPUT), +//multiplexed LCD_DE + DEFAULT_PINMUX(LCD_M1, RSVD1, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(LCD_PCLK, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_PWR0, DISPLAYA, NORMAL, NORMAL, INPUT), +//multiplexed VI_VSYNC +#ifdef COLIBRI_T30_VI + DEFAULT_PINMUX(LCD_PWR1, RSVD1, NORMAL, TRISTATE, OUTPUT), +#else + DEFAULT_PINMUX(LCD_PWR1, RSVD1, NORMAL, NORMAL, INPUT), +#endif + DEFAULT_PINMUX(LCD_PWR2, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ + DEFAULT_PINMUX(LCD_SCK, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_SDIN, RSVD, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_SDOUT, DISPLAYA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(LCD_VSYNC, DISPLAYA, NORMAL, NORMAL, INPUT), +//multiplexed with SDMMC3_DAT4 gated GMI_WR_N +#if !defined(CONFIG_CAN_SJA1000) && !defined(CONFIG_CAN_SJA1000_MODULE) + DEFAULT_PINMUX(LCD_WR_N, RSVD, NORMAL, NORMAL, INPUT), +#else /* CONFIG_CAN_SJA1000 & CONFIG_CAN_SJA1000_MODULE */ + DEFAULT_PINMUX(LCD_WR_N, RSVD, NORMAL, TRISTATE, INPUT), +#endif /* CONFIG_CAN_SJA1000 & CONFIG_CAN_SJA1000_MODULE */ +//multiplexed GMI_CLK + DEFAULT_PINMUX(OWR, OWR, NORMAL, NORMAL, INPUT), +//GPIO DD2: LAN_VBUS + DEFAULT_PINMUX(PEX_L0_CLKREQ_N, RSVD2, NORMAL, NORMAL, OUTPUT), +//GPIO DD0: LAN_RESET + DEFAULT_PINMUX(PEX_L0_PRSNT_N, RSVD2, NORMAL, NORMAL, OUTPUT), +//GPIO DD1: LAN_EXTWAKEUP + DEFAULT_PINMUX(PEX_L0_RST_N, RSVD2, NORMAL, NORMAL, INPUT), +//multiplexed VI_D9 +#ifdef COLIBRI_T30_VI + DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD2, NORMAL, TRISTATE, OUTPUT), +#else + DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD2, NORMAL, NORMAL, INPUT), +#endif + DEFAULT_PINMUX(PEX_L1_PRSNT_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */ +#ifdef COLIBRI_T30_VI +//multiplexed VI_D10 + DEFAULT_PINMUX(PEX_L1_RST_N, RSVD2, NORMAL, TRISTATE, OUTPUT), +//multiplexed VI_HSYNC + DEFAULT_PINMUX(PEX_L2_CLKREQ_N, RSVD2, NORMAL, TRISTATE, OUTPUT), +#else + DEFAULT_PINMUX(PEX_L1_RST_N, RSVD2, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_L2_CLKREQ_N, RSVD2, NORMAL, NORMAL, INPUT), +#endif + DEFAULT_PINMUX(PEX_L2_PRSNT_N, RSVD2, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(PEX_L2_RST_N, RSVD2, PULL_UP, NORMAL, INPUT), +//GPIO DD3: LAN_PME + DEFAULT_PINMUX(PEX_WAKE_N, RSVD2, NORMAL, NORMAL, INPUT), + +/* Power I2C pinmux */ + I2C_PINMUX(PWR_I2C_SCL, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + I2C_PINMUX(PWR_I2C_SDA, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE), + +#ifdef COLIBRI_T30_VI +//multiplexed VI_PCLK + DEFAULT_PINMUX(SDMMC1_CLK, RSVD1, NORMAL, TRISTATE, OUTPUT), +//multiplexed VI_D1 + DEFAULT_PINMUX(SDMMC1_CMD, RSVD1, NORMAL, TRISTATE, OUTPUT), +//multiplexed VI_D2 + DEFAULT_PINMUX(SDMMC1_DAT0, RSVD1, NORMAL, TRISTATE, OUTPUT), +//multiplexed VI_D3 + DEFAULT_PINMUX(SDMMC1_DAT1, RSVD1, NORMAL, TRISTATE, OUTPUT), +//multiplexed VI_D4 + DEFAULT_PINMUX(SDMMC1_DAT2, RSVD1, NORMAL, TRISTATE, OUTPUT), +//multiplexed VI_D5 + DEFAULT_PINMUX(SDMMC1_DAT3, RSVD1, NORMAL, TRISTATE, OUTPUT), +#else + DEFAULT_PINMUX(SDMMC1_CLK, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_CMD, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_DAT0, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_DAT1, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_DAT2, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC1_DAT3, RSVD1, NORMAL, NORMAL, INPUT), +#endif + + DEFAULT_PINMUX(SDMMC3_CLK, PWM2, NORMAL, NORMAL, INPUT), +//multiplexed VI_D6 +#ifdef COLIBRI_T30_VI + DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, NORMAL, TRISTATE, OUTPUT), +#else + DEFAULT_PINMUX(SDMMC3_CMD, PWM3, NORMAL, NORMAL, INPUT), +#endif + DEFAULT_PINMUX(SDMMC3_DAT0, RSVD0, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT1, RSVD0, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC3_DAT2, PWM1, NORMAL, NORMAL, INPUT), +//multiplexed VI_D7 +#ifdef COLIBRI_T30_VI + DEFAULT_PINMUX(SDMMC3_DAT3, RSVD0, NORMAL, TRISTATE, OUTPUT), +#else + DEFAULT_PINMUX(SDMMC3_DAT3, PWM0, NORMAL, NORMAL, INPUT), +#endif +#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE) +//not tri-stating GMI_WR_N on nPWE SODIMM pin 99 + DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT), +#else /* CONFIG_CAN_SJA1000) | CONFIG_CAN_SJA1000_MODULE */ +//tri-stating GMI_WR_N on nPWE SODIMM pin 99 + DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, PULL_UP, TRISTATE, OUTPUT), +#endif /* CONFIG_CAN_SJA1000) | CONFIG_CAN_SJA1000_MODULE */ +//not tri-stating GMI_WR_N on RDnWR SODIMM pin 93 + DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT), +//multiplexed ULPI_STP used as SSPFRM + DEFAULT_PINMUX(SDMMC3_DAT6, SPDIF, NORMAL, TRISTATE, OUTPUT), +//multiplexed ULPI_CLK used as SSPTXD + DEFAULT_PINMUX(SDMMC3_DAT7, SPDIF, NORMAL, TRISTATE, OUTPUT), + +//eMMC +#ifdef COLIBRI_T30_SDMMC4B + DEFAULT_PINMUX(SDMMC4_CLK, NAND, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_CMD, NAND, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_DAT0, GMI, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_DAT1, GMI, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_DAT2, GMI, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_DAT3, GMI, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_DAT4, GMI, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_DAT5, VGP3, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_DAT6, VGP4, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_DAT7, VGP5, NORMAL, TRISTATE, OUTPUT), + DEFAULT_PINMUX(SDMMC4_RST_N, RSVD1, NORMAL, TRISTATE, OUTPUT), +#else /* COLIBRI_T30_SDMMC4B */ + DEFAULT_PINMUX(SDMMC4_CLK, SDMMC4, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT0, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT1, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT2, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT3, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT4, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT5, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT6, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_DAT7, SDMMC4, PULL_UP, NORMAL, INPUT), + DEFAULT_PINMUX(SDMMC4_RST_N, RSVD1, PULL_DOWN, NORMAL, INPUT), +#endif /* COLIBRI_T30_SDMMC4B */ + +//GPIO K6: USB_ID, multiplexed ACC1_DETECT + DEFAULT_PINMUX(SPDIF_IN, HDA, PULL_UP, NORMAL, INPUT), +//GPIO K5: USBC_DET(VBUS), multiplexed USB1_VBUS + DEFAULT_PINMUX(SPDIF_OUT, RSVD1, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(SPI1_CS0_N, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI1_MISO, RSVD3, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI1_MOSI, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(SPI1_SCK, GMI, NORMAL, NORMAL, INPUT), +//multiplexed LCD_D18 + DEFAULT_PINMUX(SPI2_CS0_N, GMI, NORMAL, TRISTATE, OUTPUT), +//GPIO W2: USBH_PEN + DEFAULT_PINMUX(SPI2_CS1_N, SPI2, PULL_UP, NORMAL, INPUT), +//GPIO W3: USBH_OC + DEFAULT_PINMUX(SPI2_CS2_N, SPI2, NORMAL, NORMAL, INPUT), +//multiplexed LCD_D20 + DEFAULT_PINMUX(SPI2_MISO, GMI, NORMAL, TRISTATE, OUTPUT), +//multiplexed LCD_D21 + DEFAULT_PINMUX(SPI2_MOSI, GMI, NORMAL, TRISTATE, OUTPUT), +//multiplexed LCD_D19 + DEFAULT_PINMUX(SPI2_SCK, GMI, NORMAL, TRISTATE, OUTPUT), + + DEFAULT_PINMUX(SYS_CLK_REQ, SYSCLK, NORMAL, TRISTATE, OUTPUT), + + DEFAULT_PINMUX(UART2_CTS_N, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(UART2_RTS_N, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(UART2_TXD, IRDA, NORMAL, NORMAL, INPUT), + + DEFAULT_PINMUX(UART3_CTS_N, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(UART3_RTS_N, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(UART3_RXD, GMI, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(UART3_TXD, GMI, NORMAL, NORMAL, INPUT), + +//multiplexed SDMMC3_DAT7 + DEFAULT_PINMUX(ULPI_CLK, SPI1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA0, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA1, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA2, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA3, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA4, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA5, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA6, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DATA7, UARTA, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_DIR, SPI1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(ULPI_NXT, SPI1, NORMAL, NORMAL, INPUT), +//multiplexed SDMMC3_DAT6 + DEFAULT_PINMUX(ULPI_STP, SPI1, NORMAL, NORMAL, INPUT), + +//VI pins are all input level-shifted and multiplexed +//unused VI pins could disable input drivers + VI_PINMUX(VI_D0, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D1, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D2, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D3, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D4, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D5, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D6, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D7, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D8, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D9, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D10, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_D11, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_HSYNC, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), +//GPIO T1: EN_MIC_GND + DEFAULT_PINMUX(VI_MCLK, VI, NORMAL, NORMAL, OUTPUT), + VI_PINMUX(VI_PCLK, VI, PULL_UP, TRISTATE, INPUT, DISABLE, DISABLE), + VI_PINMUX(VI_VSYNC, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE), +}; + +#define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \ + { \ + .gpio_nr = _gpio, \ + .is_input = _is_input, \ + .value = _value, \ + } + +static struct gpio_init_pin_info colibri_t30_init_gpio_mode[] = { +}; + +static void __init colibri_t30_gpio_init_configure(void) +{ + int len; + int i; + struct gpio_init_pin_info *pins_info; + + len = ARRAY_SIZE(colibri_t30_init_gpio_mode); + pins_info = colibri_t30_init_gpio_mode; + + for (i = 0; i < len; ++i) { + tegra_gpio_init_configure(pins_info->gpio_nr, + pins_info->is_input, + pins_info->value); + pins_info++; + } +} + +int __init colibri_t30_pinmux_init(void) +{ + colibri_t30_gpio_init_configure(); + + tegra_pinmux_config_table(colibri_t30_pinmux, + ARRAY_SIZE(colibri_t30_pinmux)); + tegra_drive_pinmux_config_table(colibri_t30_drive_pinmux, + ARRAY_SIZE(colibri_t30_drive_pinmux)); + + return 0; +} diff --git a/arch/arm/mach-tegra/board-colibri_t30-power.c b/arch/arm/mach-tegra/board-colibri_t30-power.c new file mode 100644 index 000000000000..9a76b110cbf6 --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t30-power.c @@ -0,0 +1,503 @@ +/* + * arch/arm/mach-tegra/board-colibri_t30-power.c + * + * Copyright (C) 2012 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <asm/mach-types.h> + +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/mfd/max77663-core.h> +#include <linux/mfd/tps6591x.h> +#include <linux/pda_power.h> +#include <linux/platform_device.h> +//#include <linux/power/gpio-charger.h> +#include <linux/regulator/fixed.h> +//#include <linux/regulator/gpio-switch-regulator.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/tps62360.h> +#include <linux/regulator/tps6591x-regulator.h> +#include <linux/resource.h> + +#include <mach/edp.h> +#include <mach/iomap.h> +#include <mach/irqs.h> +#include <mach/pinmux.h> + +#include "board-colibri_t30.h" +#include "board.h" +#include "gpio-names.h" +#include "tegra3_tsensor.h" +#include "pm.h" +#include "wakeups.h" +#include "wakeups-t3.h" + +#define PMC_CTRL 0x0 +#define PMC_CTRL_INTR_LOW (1 << 17) + +/* SW1: +V1.35_VDDIO_DDR */ +static struct regulator_consumer_supply tps6591x_vdd1_supply_0[] = { + REGULATOR_SUPPLY("mem_vddio_ddr", NULL), + REGULATOR_SUPPLY("t30_vddio_ddr", NULL), +}; + +/* SW2: unused */ +static struct regulator_consumer_supply tps6591x_vdd2_supply_0[] = { + REGULATOR_SUPPLY("unused_rail_vdd2", NULL), +}; + +/* SW CTRL: +V1.0_VDD_CPU */ +static struct regulator_consumer_supply tps6591x_vddctrl_supply_0[] = { + REGULATOR_SUPPLY("vdd_cpu_pmu", NULL), + REGULATOR_SUPPLY("vdd_cpu", NULL), +//!=vddio_sys! + REGULATOR_SUPPLY("vdd_sys", NULL), +}; + +/* SWIO: +V1.8 */ +static struct regulator_consumer_supply tps6591x_vio_supply_0[] = { + REGULATOR_SUPPLY("vdd_gen1v8", NULL), + REGULATOR_SUPPLY("avdd_usb_pll", NULL), + REGULATOR_SUPPLY("avdd_osc", NULL), + REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.3"), + REGULATOR_SUPPLY("pwrdet_sdmmc4", NULL), + REGULATOR_SUPPLY("vdd1v8_satelite", NULL), + REGULATOR_SUPPLY("vddio_vi", NULL), + REGULATOR_SUPPLY("pwrdet_vi", NULL), + REGULATOR_SUPPLY("ldo1", NULL), + REGULATOR_SUPPLY("ldo2", NULL), + REGULATOR_SUPPLY("ldo6", NULL), + REGULATOR_SUPPLY("ldo7", NULL), + REGULATOR_SUPPLY("ldo8", NULL), + REGULATOR_SUPPLY("vcore_audio", NULL), + REGULATOR_SUPPLY("avcore_audio", NULL), + REGULATOR_SUPPLY("vcore1_lpddr2", NULL), + REGULATOR_SUPPLY("vcom_1v8", NULL), + REGULATOR_SUPPLY("pmuio_1v8", NULL), + REGULATOR_SUPPLY("avdd_ic_usb", NULL), +}; + +/* unused */ +static struct regulator_consumer_supply tps6591x_ldo1_supply_0[] = { + REGULATOR_SUPPLY("unused_rail_ldo1", NULL), +}; + +/* EN_+V3.3 switching via FET: +V3.3_AUDIO_AVDD_S, +V3.3 and +V1.8_VDD_LAN + see also v3_3 fixed supply */ +static struct regulator_consumer_supply tps6591x_ldo2_supply_0[] = { + REGULATOR_SUPPLY("en_V3_3", NULL), +}; + +/* unused in Colibri T30, used in Apalis T30 */ +static struct regulator_consumer_supply tps6591x_ldo3_supply_0[] = { + REGULATOR_SUPPLY("avdd_dsi_csi", NULL), + REGULATOR_SUPPLY("pwrdet_mipi", NULL), +}; + +/* +V1.2_VDD_RTC */ +static struct regulator_consumer_supply tps6591x_ldo4_supply_0[] = { + REGULATOR_SUPPLY("vdd_rtc", NULL), +}; + +/* +V2.8_AVDD_VDAC */ +//only required for analog RGB +static struct regulator_consumer_supply tps6591x_ldo5_supply_0[] = { + REGULATOR_SUPPLY("avdd_vdac", NULL), +}; + +/* +V1.05_AVDD_PLLE */ +static struct regulator_consumer_supply tps6591x_ldo6_supply_0[] = { + REGULATOR_SUPPLY("avdd_plle", NULL), +}; + +/* +V1.2_AVDD_PLL */ +static struct regulator_consumer_supply tps6591x_ldo7_supply_0[] = { + REGULATOR_SUPPLY("avdd_plla_p_c_s", NULL), + REGULATOR_SUPPLY("avdd_pllm", NULL), + REGULATOR_SUPPLY("avdd_pllu_d", NULL), + REGULATOR_SUPPLY("avdd_pllu_d2", NULL), + REGULATOR_SUPPLY("avdd_pllx", NULL), +}; + +/* +V1.0_VDD_DDR_HS */ +static struct regulator_consumer_supply tps6591x_ldo8_supply_0[] = { + REGULATOR_SUPPLY("vdd_ddr_hs", NULL), +}; + +#define TPS_PDATA_INIT(_name, _sname, _minmv, _maxmv, _supply_reg, _always_on, \ + _boot_on, _apply_uv, _init_uV, _init_enable, _init_apply, _ectrl, _flags) \ + static struct tps6591x_regulator_platform_data pdata_##_name##_##_sname = \ + { \ + .regulator = { \ + .constraints = { \ + .min_uV = (_minmv)*1000, \ + .max_uV = (_maxmv)*1000, \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL | \ + REGULATOR_MODE_STANDBY), \ + .valid_ops_mask = (REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_STATUS | \ + REGULATOR_CHANGE_VOLTAGE), \ + .always_on = _always_on, \ + .boot_on = _boot_on, \ + .apply_uV = _apply_uv, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(tps6591x_##_name##_supply_##_sname), \ + .consumer_supplies = tps6591x_##_name##_supply_##_sname, \ + .supply_regulator = _supply_reg, \ + }, \ + .init_uV = _init_uV * 1000, \ + .init_enable = _init_enable, \ + .init_apply = _init_apply, \ + .ectrl = _ectrl, \ + .flags = _flags, \ + } + +TPS_PDATA_INIT(vdd1, 0, 1350, 1350, 0, 1, 1, 0, -1, 0, 0, 0, 0); +TPS_PDATA_INIT(vdd2, 0, 1050, 1050, 0, 0, 1, 0, -1, 0, 0, EXT_CTRL_SLEEP_OFF, 0); +TPS_PDATA_INIT(vddctrl, 0, 800, 1300, 0, 1, 1, 0, -1, 0, 0, EXT_CTRL_EN1, 0); +TPS_PDATA_INIT(vio, 0, 1800, 1800, 0, 1, 1, 0, -1, 0, 0, 0, 0); + +TPS_PDATA_INIT(ldo1, 0, 1000, 3300, tps6591x_rails(VIO), 0, 0, 0, -1, 0, 1, 0, 0); +/* Make sure EN_+V3.3 is always on! */ +TPS_PDATA_INIT(ldo2, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 1, 0, 0); + +TPS_PDATA_INIT(ldo3, 0, 1200, 1200, 0, 0, 0, 0, -1, 0, 0, 0, 0); +TPS_PDATA_INIT(ldo4, 0, 900, 1400, 0, 1, 0, 0, -1, 0, 0, 0, LDO_LOW_POWER_ON_SUSPEND); +TPS_PDATA_INIT(ldo5, 0, 2800, 2800, 0, 0, 0, 0, -1, 0, 0, 0, 0); +/* AVDD_PLLE should be 1.05V, but ldo_6 can not be adjusted in a 50mV granularity */ +TPS_PDATA_INIT(ldo6, 0, 1000, 1100, tps6591x_rails(VIO), 0, 0, 1, -1, 0, 0, 0, 0); + +TPS_PDATA_INIT(ldo7, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 0, EXT_CTRL_SLEEP_OFF, LDO_LOW_POWER_ON_SUSPEND); +TPS_PDATA_INIT(ldo8, 0, 1000, 1000, tps6591x_rails(VIO), 1, 0, 0, -1, 0, 0, EXT_CTRL_SLEEP_OFF, LDO_LOW_POWER_ON_SUSPEND); + +#if defined(CONFIG_RTC_DRV_TPS6591x) +static struct tps6591x_rtc_platform_data rtc_data = { + .irq = TPS6591X_IRQ_BASE + TPS6591X_INT_RTC_ALARM, + .time = { + .tm_year = 2000, + .tm_mon = 0, + .tm_mday = 1, + .tm_hour = 0, + .tm_min = 0, + .tm_sec = 0, + }, +}; + +#define TPS_RTC_REG() \ + { \ + .id = 0, \ + .name = "rtc_tps6591x", \ + .platform_data = &rtc_data, \ + } +#endif + +#define TPS_REG(_id, _name, _sname) \ + { \ + .id = TPS6591X_ID_##_id, \ + .name = "tps6591x-regulator", \ + .platform_data = &pdata_##_name##_##_sname, \ + } + +static struct tps6591x_subdev_info colibri_t30_tps_devs[] = { + TPS_REG(VDD_1, vdd1, 0), + TPS_REG(VDD_2, vdd2, 0), + TPS_REG(VDDCTRL, vddctrl, 0), + TPS_REG(VIO, vio, 0), + TPS_REG(LDO_1, ldo1, 0), + TPS_REG(LDO_2, ldo2, 0), + TPS_REG(LDO_3, ldo3, 0), + TPS_REG(LDO_4, ldo4, 0), + TPS_REG(LDO_5, ldo5, 0), + TPS_REG(LDO_6, ldo6, 0), + TPS_REG(LDO_7, ldo7, 0), + TPS_REG(LDO_8, ldo8, 0), +#if defined(CONFIG_RTC_DRV_TPS6591x) + TPS_RTC_REG(), +#endif +}; + +static struct tps6591x_sleep_keepon_data tps_slp_keepon = { + .clkout32k_keepon = 1, +}; + +static struct tps6591x_platform_data tps_platform = { + .irq_base = TPS6591X_IRQ_BASE, + .gpio_base = TPS6591X_GPIO_BASE, + .dev_slp_en = true, + .slp_keepon = &tps_slp_keepon, + .use_power_off = true, +}; + +static struct i2c_board_info __initdata colibri_t30_regulators[] = { + { + I2C_BOARD_INFO("tps6591x", 0x2D), +//PWR_INT_IN wake18 + .irq = INT_EXTERNAL_PMU, + .platform_data = &tps_platform, + }, +}; + +/* TPS62362 DC-DC converter + SW: +V1.2_VDD_CORE + Note: Colibri T30 V1.0 have TPS62360 with different voltage levels at startup */ +static struct regulator_consumer_supply tps6236x_dcdc_supply[] = { + REGULATOR_SUPPLY("vdd_core", NULL), +}; + +static struct tps62360_regulator_platform_data tps6236x_pdata = { + .reg_init_data = { \ + .constraints = { \ + .min_uV = 900000, \ + .max_uV = 1400000, \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL | \ + REGULATOR_MODE_STANDBY), \ + .valid_ops_mask = (REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_STATUS | \ + REGULATOR_CHANGE_VOLTAGE), \ + .always_on = 1, \ + .boot_on = 1, \ + .apply_uV = 0, \ + }, \ + .num_consumer_supplies = ARRAY_SIZE(tps6236x_dcdc_supply), \ + .consumer_supplies = tps6236x_dcdc_supply, \ + }, \ + .en_discharge = true, \ + .vsel0_gpio = -1, \ + .vsel1_gpio = -1, \ + .vsel0_def_state = 1, \ + .vsel1_def_state = 1, \ +}; + +static struct i2c_board_info __initdata tps6236x_boardinfo[] = { + { + I2C_BOARD_INFO("tps62360", 0x60), + .platform_data = &tps6236x_pdata, + }, +}; + +/* Macro for defining fixed regulator sub device data */ +#define FIXED_SUPPLY(_name) "fixed_reg_"#_name +#define FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, \ + _boot_on, _gpio_nr, _active_high, _boot_state, \ + _millivolts, _od_state) \ + static struct regulator_init_data ri_data_##_var = \ + { \ + .supply_regulator = _in_supply, \ + .num_consumer_supplies = \ + ARRAY_SIZE(fixed_reg_##_name##_supply), \ + .consumer_supplies = fixed_reg_##_name##_supply, \ + .constraints = { \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL), \ + .valid_ops_mask = (REGULATOR_CHANGE_STATUS), \ + .always_on = _always_on, \ + .boot_on = _boot_on, \ + }, \ + }; \ + static struct fixed_voltage_config fixed_reg_##_var##_pdata = \ + { \ + .supply_name = FIXED_SUPPLY(_name), \ + .microvolts = _millivolts * 1000, \ + .gpio = _gpio_nr, \ + .enable_high = _active_high, \ + .enabled_at_boot = _boot_state, \ + .init_data = &ri_data_##_var, \ + .gpio_is_open_drain = _od_state, \ + }; \ + static struct platform_device fixed_reg_##_var##_dev = { \ + .name = "reg-fixed-voltage", \ + .id = _id, \ + .dev = { \ + .platform_data = &fixed_reg_##_var##_pdata, \ + }, \ + } + +#define FIXED_REG(_id, _var, _name, _in_supply, _always_on, _boot_on, \ + _gpio_nr, _active_high, _boot_state, _millivolts) \ + FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, _boot_on, \ + _gpio_nr, _active_high, _boot_state, _millivolts, false) + +#define ADD_FIXED_REG(_name) (&fixed_reg_##_name##_dev) + +/* PMU GP6: EN_VDD_HDMI switching via FET: +V1.8_AVDD_HDMI_PLL and +V3.3_AVDD_HDMI */ +static struct regulator_consumer_supply fixed_reg_en_hdmi_supply[] = { + REGULATOR_SUPPLY("avdd_hdmi", NULL), + REGULATOR_SUPPLY("avdd_hdmi_pll", NULL), +// REGULATOR_SUPPLY("vdd_3v3_hdmi_cec", NULL), +}; + +//EN_VDD_CORE PMIC GPIO2 +//EN_VDD_FUSE PMIC GPIO4 +//EN_VDD_HDMI PMIC GPIO6 + +FIXED_REG(2, en_hdmi, en_hdmi, NULL, 0, 0, TPS6591X_GPIO_6, true, 1, 1800); + +/* +V3.3 is switched on by LDO2, As this can not be modeled we use a fixed + regulator without enable, 3.3V must not be switched off anyway. ++V3.3: +VDD_DDR_RX +VDDIO_LCD_1 +VDDIO_LCD_2 +VDDIO_CAM +LM95245 +VDDIO_SYS_01 +VDDIO_SYS_02 +VDDIO_BB +VDDIO_AUDIO +VDDIO_GMI_1 +VDDIO_GMI_2 +VDDIO_GMI_3 +VDDIO_UART +VDDIO_SDMMC1 +AVDD_USB +VDDIO_SDMMC3 +74AVCAH164245 +VDDIO_PEX_CTL +TPS65911 VDDIO +MT29F16G08 +SGTL5000 VDDIO +STMPE811 +AX88772B VCC3x +SDIN5D2-2G VCCx */ +static struct regulator_consumer_supply fixed_reg_v3_3_supply[] = { + REGULATOR_SUPPLY("avdd_audio", NULL), + REGULATOR_SUPPLY("avdd_usb", NULL), + REGULATOR_SUPPLY("vddio_sd_slot", "sdhci-tegra.1"), + REGULATOR_SUPPLY("vddio_sys", NULL), + REGULATOR_SUPPLY("vddio_uart", NULL), + REGULATOR_SUPPLY("pwrdet_uart", NULL), + REGULATOR_SUPPLY("vddio_audio", NULL), + REGULATOR_SUPPLY("pwrdet_audio", NULL), + REGULATOR_SUPPLY("vddio_bb", NULL), + REGULATOR_SUPPLY("pwrdet_bb", NULL), + REGULATOR_SUPPLY("vddio_lcd_pmu", NULL), + REGULATOR_SUPPLY("pwrdet_lcd", NULL), + REGULATOR_SUPPLY("vddio_cam", NULL), + REGULATOR_SUPPLY("pwrdet_cam", NULL), + /* if this supply is defined, the sdhci driver tries + * to set it to 1.8V */ +// REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.1"), + REGULATOR_SUPPLY("pwrdet_sdmmc2", NULL), + REGULATOR_SUPPLY("pwrdet_sdmmc1", NULL), + REGULATOR_SUPPLY("pwrdet_sdmmc3", NULL), + REGULATOR_SUPPLY("pwrdet_pex_ctl", NULL), + REGULATOR_SUPPLY("pwrdet_nand", NULL), + + /* SGTL5000 */ + REGULATOR_SUPPLY("VDDA", "4-000a"), + REGULATOR_SUPPLY("VDDIO", "4-000a"), +}; + +FIXED_REG(3, v3_3, v3_3, NULL, 1, 1, -1, true, 1, 3300); + +/* Gpio switch regulator platform data */ +static struct platform_device *fixed_reg_devs_colibri_t30[] = { + ADD_FIXED_REG(en_hdmi), + ADD_FIXED_REG(v3_3), +}; + +int __init colibri_t30_regulator_init(void) +{ + void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); + u32 pmc_ctrl; + + /* configure the power management controller to trigger PMU + * interrupts when low */ + + pmc_ctrl = readl(pmc + PMC_CTRL); + writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL); + + /* The regulator details have complete constraints */ + regulator_has_full_constraints(); + + tps_platform.num_subdevs = + ARRAY_SIZE(colibri_t30_tps_devs); + tps_platform.subdevs = colibri_t30_tps_devs; + + i2c_register_board_info(4, colibri_t30_regulators, 1); + + /* Register the TPS6236x. */ + pr_info("Registering the device TPS62360\n"); + i2c_register_board_info(4, tps6236x_boardinfo, 1); + + return 0; +} + +int __init colibri_t20_fixed_regulator_init(void) +{ + return platform_add_devices(fixed_reg_devs_colibri_t30, ARRAY_SIZE(fixed_reg_devs_colibri_t30)); +} +subsys_initcall_sync(colibri_t20_fixed_regulator_init); + +static void colibri_t30_board_suspend(int lp_state, enum suspend_stage stg) +{ + if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_SUSPEND_BEFORE_CPU)) + tegra_console_uart_suspend(); +} + +static void colibri_t30_board_resume(int lp_state, enum resume_stage stg) +{ + if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_RESUME_AFTER_CPU)) + tegra_console_uart_resume(); +} + +static struct tegra_suspend_platform_data colibri_t30_suspend_data = { + .cpu_timer = 2000, + .cpu_off_timer = 200, + .suspend_mode = TEGRA_SUSPEND_LP1, + .core_timer = 0x7e7e, + .core_off_timer = 0, + .corereq_high = true, + .sysclkreq_high = true, + .cpu_lp2_min_residency = 2000, + .board_suspend = colibri_t30_board_suspend, + .board_resume = colibri_t30_board_resume, +}; + +int __init colibri_t30_suspend_init(void) +{ + /* Make core_pwr_req to high */ + colibri_t30_suspend_data.corereq_high = true; + + /* CORE_PWR_REQ to be high required to enable the dc-dc converter tps62361x */ + colibri_t30_suspend_data.corereq_high = true; + +//required? + colibri_t30_suspend_data.cpu_timer = 5000; + colibri_t30_suspend_data.cpu_off_timer = 5000; + + tegra_init_suspend(&colibri_t30_suspend_data); + return 0; +} + +#ifdef CONFIG_TEGRA_EDP_LIMITS +int __init colibri_t30_edp_init(void) +{ + unsigned int regulator_mA; + + regulator_mA = get_maximum_cpu_current_supported(); + if (!regulator_mA) { + regulator_mA = 6000; /* regular T30/s */ + } + pr_info("%s: CPU regulator %d mA\n", __func__, regulator_mA); + + tegra_init_cpu_edp_limits(regulator_mA); + return 0; +} +#endif diff --git a/arch/arm/mach-tegra/board-colibri_t30.c b/arch/arm/mach-tegra/board-colibri_t30.c new file mode 100644 index 000000000000..db3ab08cbc3d --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t30.c @@ -0,0 +1,1556 @@ +/* + * arch/arm/mach-tegra/board-colibri_t30.c + * + * Copyright (c) 2012-2013 Toradex, Inc. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <linux/can/platform/mcp251x.h> +#include <linux/can/platform/sja1000.h> +#include <linux/clk.h> +#include <linux/colibri_usb.h> +#include <linux/types.h> /* required by linux/gpio_keys.h */ +#include <linux/gpio_keys.h> +#include <linux/i2c.h> +#include <linux/i2c-tegra.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/leds_pwm.h> +#include <linux/lm95245.h> +#include <linux/mfd/stmpe.h> +#include <linux/platform_data/tegra_usb.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/spi/spi.h> +#include <linux/spi-tegra.h> +#include <linux/tegra_uart.h> + +#include <mach/io_dpd.h> +#include <mach/sdhci.h> +#include <mach/tegra_asoc_pdata.h> +#include <mach/tegra_fiq_debugger.h> +#include <mach/thermal.h> +#include <mach/usb_phy.h> +#include <mach/w1.h> + +#include <media/soc_camera.h> +#include <media/tegra_v4l2_camera.h> +#include <linux/input/fusion_F0710A.h> + +#include "board-colibri_t30.h" +#include "board.h" +#include "clock.h" +#include "devices.h" +#include "gpio-names.h" +#include "pm.h" + +//from former drivers/mtd/maps/tegra_nor.h +#define TEGRA_GMI_PHYS 0x70009000 +#define TEGRA_GMI_BASE IO_TO_VIRT(TEGRA_GMI_PHYS) +#define TEGRA_SNOR_CONFIG_REG (TEGRA_GMI_BASE + 0x00) + +//from drivers/mtd/maps/tegra_nor.c +#define __BITMASK0(len) (BIT(len) - 1) +#define REG_FIELD(val, start, len) (((val) & __BITMASK0(len)) << (start)) + +#define TEGRA_SNOR_CONFIG_GO BIT(31) +#define TEGRA_SNOR_CONFIG_SNOR_CS(val) REG_FIELD((val), 4, 3) + +/* Audio */ + +static struct tegra_asoc_platform_data colibri_t30_audio_sgtl5000_pdata = { + .gpio_spkr_en = -1, + .gpio_hp_det = -1, + .gpio_hp_mute = -1, + .gpio_int_mic_en = -1, + .gpio_ext_mic_en = -1, + .i2s_param[HIFI_CODEC] = { + .audio_port_id = 0, /* index of below registered + tegra_i2s_device */ + .i2s_mode = TEGRA_DAIFMT_I2S, + .is_i2s_master = 1, + .sample_size = 16, + }, + .i2s_param[BASEBAND] = { + .audio_port_id = -1, + }, + .i2s_param[BT_SCO] = { + .audio_port_id = -1, + }, +}; + +static struct platform_device colibri_t30_audio_sgtl5000_device = { + .name = "tegra-snd-colibri_t30-sgtl5000", + .id = 0, + .dev = { + .platform_data = &colibri_t30_audio_sgtl5000_pdata, + }, +}; + +/* Camera */ + +#ifdef CONFIG_TEGRA_CAMERA +static struct platform_device tegra_camera = { + .name = "tegra_camera", + .id = -1, +}; +#endif /* CONFIG_TEGRA_CAMERA */ + +#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE) +static void tegra_camera_disable(struct nvhost_device *ndev) +{ +} + +static int tegra_camera_enable(struct nvhost_device *ndev) +{ + return 0; +} + +static struct tegra_camera_platform_data tegra_camera_platform_data = { + .disable_camera = tegra_camera_disable, + .enable_camera = tegra_camera_enable, + .flip_h = 0, + .flip_v = 0, + .port = TEGRA_CAMERA_PORT_VIP, +}; + +#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE) +static struct i2c_board_info camera_i2c_max9526 = { + I2C_BOARD_INFO("max9526", 0x21), +}; + +static struct soc_camera_link iclink_max9526 = { + .board_info = &camera_i2c_max9526, + .bus_id = -1, /* This must match the .id of tegra_vi01_device */ + .i2c_adapter_id = 0, +}; + +static struct platform_device soc_camera_max9526 = { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &iclink_max9526, + }, +}; +#endif /* CONFIG_SOC_CAMERA_MAX9526 | CONFIG_SOC_CAMERA_MAX9526_MODULE */ + +#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE) +static struct i2c_board_info camera_i2c_adv7180 = { + I2C_BOARD_INFO("adv7180", 0x21), +}; + +static struct soc_camera_link iclink_adv7180 = { + .board_info = &camera_i2c_adv7180, + .bus_id = -1, /* This must match the .id of tegra_vi01_device */ + .i2c_adapter_id = 0, +}; + +static struct platform_device soc_camera_adv7180 = { + .name = "soc-camera-pdrv", + .id = 1, + .dev = { + .platform_data = &iclink_adv7180, + }, +}; +#endif /* CONFIG_VIDEO_ADV7180 | CONFIG_VIDEO_ADV7180_MODULE */ +#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */ + +/* CAN */ +#if ((defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)) && \ + (defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE))) + #error either enable MCP251X or SJA1000 but not both +#endif + +#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE) +/* Colibri EvalBoard V3.1a */ + +#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PS0 /* active low interrupt (MCP2515 nINT) */ +#define CAN_RESET_GPIO TEGRA_GPIO_PK4 /* active high reset (not MCP2515 nRESET) */ + +static int __init colibri_t20_mcp2515_setup(struct spi_device *spi) +{ + int gpio_status; + + printk("Colibri EvalBoard V3.1a CAN Initialisation\n"); + + /* configure MCP2515 reset line as output and pull high into reset */ + gpio_status = gpio_request(CAN_RESET_GPIO, "CAN_RESET_GPIO"); + if (gpio_status < 0) + pr_warning("CAN_RESET_GPIO request GPIO FAILED\n"); + gpio_status = gpio_direction_output(CAN_RESET_GPIO, 1); + if (gpio_status < 0) + pr_warning("CAN_RESET_GPIO request GPIO DIRECTION FAILED\n"); + + udelay(2); + + /* pull out of reset */ + gpio_set_value(CAN_RESET_GPIO, 0); + + return 0; +} + +static struct mcp251x_platform_data mcp251x_pdata = { + .board_specific_setup = colibri_t20_mcp2515_setup, + .oscillator_frequency = 16000000, + .power_enable = NULL, + .transceiver_enable = NULL +}; + +static struct spi_board_info mcp251x_board_info[] = { + { + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 10000000, + .modalias = "mcp2515", + .platform_data = &mcp251x_pdata, + }, +}; + +static void __init colibri_t20_mcp2515_can_init(void) +{ + mcp251x_board_info[0].irq = gpio_to_irq(CAN_INTERRUPT_GPIO); + spi_register_board_info(mcp251x_board_info, ARRAY_SIZE(mcp251x_board_info)); +} +#else /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */ +#define colibri_t20_mcp2515_can_init() do {} while (0) +#endif /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */ + +#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE) +#define CAN_BASE_TEG 0x48000000 /* GMI_CS4_N */ +static struct resource colibri_can_resource[] = { + [0] = { + .start = CAN_BASE_TEG, /* address */ + .end = CAN_BASE_TEG + 0xff, /* data */ + .flags = IORESOURCE_MEM, + }, + [1] = { + /* interrupt assigned during initialisation */ + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, + } +}; + +static struct sja1000_platform_data colibri_can_platdata = { + .osc_freq = 24000000, + .ocr = (OCR_MODE_NORMAL | OCR_TX0_PUSHPULL), + .cdr = CDR_CLK_OFF | /* Clock off (CLKOUT pin) */ + CDR_CBP, /* CAN input comparator bypass */ +}; + +static struct platform_device colibri_can_device = { + .name = "sja1000_platform", + .id = 0, + .num_resources = ARRAY_SIZE(colibri_can_resource), + .resource = colibri_can_resource, + .dev = { + .platform_data = &colibri_can_platdata, + } +}; +#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */ + +/* Clocks */ +static struct tegra_clk_init_table colibri_t30_clk_init_table[] __initdata = { + /* name parent rate enabled */ + {"audio1", "i2s1_sync", 0, false}, + {"audio2", "i2s2_sync", 0, false}, + {"audio3", "i2s3_sync", 0, false}, + {"blink", "clk_32k", 32768, true}, + {"d_audio", "clk_m", 12000000, false}, + {"dam0", "clk_m", 12000000, false}, + {"dam1", "clk_m", 12000000, false}, + {"dam2", "clk_m", 12000000, false}, + {"hda", "pll_p", 108000000, false}, + {"hda2codec_2x","pll_p", 48000000, false}, + {"i2c1", "pll_p", 3200000, false}, + {"i2c2", "pll_p", 3200000, false}, + {"i2c3", "pll_p", 3200000, false}, + {"i2c4", "pll_p", 3200000, false}, + {"i2c5", "pll_p", 3200000, false}, + {"i2s0", "pll_a_out0", 0, false}, + {"i2s1", "pll_a_out0", 0, false}, + {"i2s2", "pll_a_out0", 0, false}, + {"i2s3", "pll_a_out0", 0, false}, + {"nor", "pll_p", 86500000, true}, + {"pll_a", NULL, 564480000, true}, + {"pll_m", NULL, 0, false}, + {"pwm", "pll_p", 3187500, false}, + {"spdif_out", "pll_a_out0", 0, false}, + {"vi", "pll_p", 0, false}, + {"vi_sensor", "pll_p", 150000000, false}, + {NULL, NULL, 0, 0}, +}; + +/* GPIO */ +/* Pins in the following struct are configured as GPIO Inputs and + * accessible from userspace through /sys/class/gpio + * Pins which likely are used with one of their alternate functions + * are commented out. + * Refer to the TRM, chapters 'Multi-Prupose Io Pins' and 'GPIO Controller' + */ +static struct gpio colibri_t30_gpios[] = { +// {TEGRA_GPIO_PA2, GPIOF_IN, "SODIMM pin 186"}, +// {TEGRA_GPIO_PA3, GPIOF_IN, "SODIMM pin 184"}, + {TEGRA_GPIO_PB2, GPIOF_IN, "SODIMM pin 154"}, +#if !defined(CONFIG_SPI_GPIO) && !defined(CONFIG_SPI_GPIO_MODULE) +//conflicts with MECS Tellurium xPOD2 SSPCLK2 +// {TEGRA_GPIO_PB6, GPIOF_IN, "SODIMM pin 55"}, +#endif +#ifndef MECS_TELLURIUM_XPOD2 +//conflicts with MECS Tellurium xPOD2 SSPFRM2 +// {TEGRA_GPIO_PB7, GPIOF_IN, "SODIMM pin 63"}, +#endif +#ifndef COLIBRI_T30_VI + {TEGRA_GPIO_PC1, GPIOF_IN, "SODIMM pin 81"}, +#endif + {TEGRA_GPIO_PI3, GPIOF_IN, "SODIMM pin 130"}, + {TEGRA_GPIO_PI6, GPIOF_IN, "SODIMM pin 132"}, + //{TEGRA_GPIO_PJ0, GPIOF_IN, "SODIMM pin 126"}, + //{TEGRA_GPIO_PJ2, GPIOF_IN, "SODIMM pin 128"}, +//conflicts with GMI_ADV_N used for multiplexed address/data bus +// {TEGRA_GPIO_PK0, GPIOF_IN, "SODIMM pin 150"}, +// {TEGRA_GPIO_PK1, GPIOF_IN, "SODIMM pin 152"}, +#ifndef CONFIG_KEYBOARD_GPIO +//conflicts with menu key +// {TEGRA_GPIO_PK6, GPIOF_IN, "SODIMM pin 135"}, +#endif +// {TEGRA_GPIO_PN0, GPIOF_IN, "SODIMM pin 174"}, +// {TEGRA_GPIO_PN1, GPIOF_IN, "SODIMM pin 176"}, +// {TEGRA_GPIO_PN2, GPIOF_IN, "SODIMM pin 178"}, +// {TEGRA_GPIO_PN3, GPIOF_IN, "SODIMM pin 180"}, +// {TEGRA_GPIO_PN4, GPIOF_IN, "SODIMM pin 160"}, +// {TEGRA_GPIO_PN5, GPIOF_IN, "SODIMM pin 158"}, + {TEGRA_GPIO_PN6, GPIOF_IN, "SODIMM pin 162"}, +//conflicts with ADDRESS13 +// {TEGRA_GPIO_PP4, GPIOF_IN, "SODIMM pin 120"}, +//conflicts with ADDRESS14 +// {TEGRA_GPIO_PP5, GPIOF_IN, "SODIMM pin 122"}, +//conflicts with ADDRESS15 +// {TEGRA_GPIO_PP6, GPIOF_IN, "SODIMM pin 124"}, +// {TEGRA_GPIO_PP7, GPIOF_IN, "SODIMM pin 188"}, +#if !defined(IRIS) && !defined(CONFIG_CAN_MCP251X) && \ + !defined(CONFIG_CAN_MCP251X_MODULE) && \ + !defined(CONFIG_CAN_SJA1000) && \ + !defined(CONFIG_CAN_SJA1000_MODULE) +//conflicts with CAN interrupt on Colibri Evaluation Board and MECS Tellurium +//xPOD1 CAN +//conflicts with DAC_PSAVE# on Iris + {TEGRA_GPIO_PS0, GPIOF_IN, "SODIMM pin 73"}, +#endif +#ifndef CONFIG_KEYBOARD_GPIO +//conflicts with back key + {TEGRA_GPIO_PT5, GPIOF_IN, "SOD-133, Iris X16-14"}, +//conflicts with home key + {TEGRA_GPIO_PT6, GPIOF_IN, "SODIMM pin 127"}, +//conflicts with power key (WAKE1) + {TEGRA_GPIO_PV1, GPIOF_IN, "SODI-45, Iris X16-20"}, +#endif +#ifndef COLIBRI_T30_VI + {TEGRA_GPIO_PW5, GPIOF_IN, "SODIMM pin 75"}, + //conflicts with BL_ON + //{TEGRA_GPIO_PV2, GPIOF_IN, "SODIMM pin 71"}, + {TEGRA_GPIO_PV3, GPIOF_IN, "SODI-85, Iris X16-18"}, +#endif +//conflicts with ADDRESS12 +// {TEGRA_GPIO_PU6, GPIOF_IN, "SODIMM pin 118"}, +//multiplexed LCD_D21 +// {TEGRA_GPIO_PX0, GPIOF_IN, "SODIMM pin 142"}, +//multiplexed LCD_D20 +// {TEGRA_GPIO_PX1, GPIOF_IN, "SODIMM pin 140"}, +//multiplexed LCD_D19 +// {TEGRA_GPIO_PX2, GPIOF_IN, "SODIMM pin 138"}, +//multiplexed LCD_D18 +// {TEGRA_GPIO_PX3, GPIOF_IN, "SODIMM pin 136"}, + {TEGRA_GPIO_PX4, GPIOF_IN, "SODIMM pin 134"}, + {TEGRA_GPIO_PX6, GPIOF_IN, "102, I X13 ForceOFF#"}, + {TEGRA_GPIO_PX7, GPIOF_IN, "104, I X14 ForceOFF#"}, +#ifndef COLIBRI_T30_VI +// {TEGRA_GPIO_PY4, GPIOF_IN, "SODI-97, Iris X16-17"}, +// {TEGRA_GPIO_PY5, GPIOF_IN, "SODI-79, Iris X16-19"}, +// {TEGRA_GPIO_PY6, GPIOF_IN, "SODI-103, Iris X16-15"}, +// {TEGRA_GPIO_PY7, GPIOF_IN, "SODI-101, Iris X16-16"}, +// {TEGRA_GPIO_PZ0, GPIOF_IN, "SODI-96"}, +// {TEGRA_GPIO_PZ1, GPIOF_IN, "SODI-98, Iris X16-13"}, +#endif +// {TEGRA_GPIO_PZ2, GPIOF_IN, "SODIMM pin 156"}, +// {TEGRA_GPIO_PZ4, GPIOF_IN, "SODIMM pin 164"}, + {TEGRA_GPIO_PBB4, GPIOF_IN, "SODIMM pin 166"}, + {TEGRA_GPIO_PBB5, GPIOF_IN, "SODIMM pin 168"}, + {TEGRA_GPIO_PBB6, GPIOF_IN, "SODIMM pin 170"}, + {TEGRA_GPIO_PBB7, GPIOF_IN, "SODIMM pin 172"}, +#ifndef COLIBRI_T30_VI +// {TEGRA_GPIO_PCC2, GPIOF_IN, "SODIMM pin 77"}, + {TEGRA_GPIO_PCC7, GPIOF_IN, "SODIMM pin 94"}, +#endif +#ifndef CONFIG_KEYBOARD_GPIO +//conflicts with volume down key + {TEGRA_GPIO_PCC6, GPIOF_IN, "SODIMM pin 24"}, +//conflicts with volume up key + {TEGRA_GPIO_PDD7, GPIOF_IN, "SODIMM pin 22"}, +#endif +#ifndef COLIBRI_T30_VI + {TEGRA_GPIO_PDD5, GPIOF_IN, "SODIMM pin 69"}, + {TEGRA_GPIO_PDD6, GPIOF_IN, "SODIMM pin 65"}, +#endif + +}; + +static void colibri_t30_gpio_init(void) +{ + int i = 0; + int length = sizeof(colibri_t30_gpios) / sizeof(struct gpio); + int err = 0; + + for (i = 0; i < length; i++) { + err = gpio_request_one(colibri_t30_gpios[i].gpio, + colibri_t30_gpios[i].flags, + colibri_t30_gpios[i].label); + + if (err) { + pr_warning("gpio_request(%s) failed, err = %d", + colibri_t30_gpios[i].label, err); + } else { + gpio_export(colibri_t30_gpios[i].gpio, true); + } + } +} + +/* + * Fusion touch screen GPIOs (using Toradex display/touch adapater) + * Iris X16-38, SODIMM pin 28 (PWM B), pen down interrupt + * Iris X16-39, SODIMM pin 30 (PWM C), reset + * gpio_request muxes the GPIO function automatically, we only have to make + * sure input/output muxing is done here... + */ +static struct fusion_f0710a_init_data colibri_fusion_pdata = { + .pinmux_fusion_pins = NULL, + .gpio_int = TEGRA_GPIO_PB5, /* SO-DIMM 28: Pen down interrupt */ + .gpio_reset = TEGRA_GPIO_PA6, /* SO-DIMM 30: Reset interrupt */ +}; + +/* I2C */ + +/* Make sure that the pinmuxing enable the 'open drain' feature for pins used + for I2C */ + +/* GEN1_I2C: I2C_SDA/SCL on SODIMM pin 194/196 (e.g. RTC on carrier board) */ +static struct i2c_board_info colibri_t30_i2c_bus1_board_info[] __initdata = { + { + /* M41T0M6 real time clock on Iris carrier board */ + I2C_BOARD_INFO("rtc-ds1307", 0x68), + .type = "m41t00", + }, + { + /* TouchRevolution Fusion 7 and 10 multi-touch controller */ + I2C_BOARD_INFO("fusion_F0710A", 0x10), + .platform_data = &colibri_fusion_pdata, + }, +}; + +static struct tegra_i2c_platform_data colibri_t30_i2c1_platform_data = { + .adapter_nr = 0, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {400000, 0}, + .bus_count = 1, + .scl_gpio = {I2C_SCL, 0}, + .sda_gpio = {I2C_SDA, 0}, + .slave_addr = 0x00FC, +}; + +/* GEN2_I2C: unused */ + +/* DDC_CLOCK/DATA on X3 pin 15/16 (e.g. display EDID) */ +static struct tegra_i2c_platform_data colibri_t30_i2c4_platform_data = { + .adapter_nr = 3, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {10000, 10000}, + .bus_count = 1, + .scl_gpio = {DDC_SCL, 0}, + .sda_gpio = {DDC_SDA, 0}, + .slave_addr = 0x00FC, +}; + +/* PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and touch screen + controller */ + +/* STMPE811 touch screen controller */ +static struct stmpe_ts_platform_data stmpe811_ts_data = { + .adc_freq = 1, /* 3.25 MHz ADC clock speed */ + .ave_ctrl = 3, /* 8 sample average control */ + .fraction_z = 7, /* 7 length fractional part in z */ + .i_drive = 1, /* 50 mA typical 80 mA max touchscreen + drivers current limit value */ + .mod_12b = 1, /* 12-bit ADC */ + .ref_sel = 0, /* internal ADC reference */ + .sample_time = 4, /* ADC converstion time: 80 clocks */ + .settling = 3, /* 1 ms panel driver settling time */ + .touch_det_delay = 5, /* 5 ms touch detect interrupt delay */ +}; + +/* STMPE811 ADC controller */ +static struct stmpe_adc_platform_data stmpe811_adc_data = { + .sample_time = 4, /* ADC converstion time: 80 clocks */ + .mod_12b = 1, /* 12-bit ADC */ + .ref_sel = 0, /* internal ADC reference */ + .adc_freq = 1, /* 3.25 MHz ADC clock speed */ +}; + +static struct stmpe_platform_data stmpe811_data = { + .blocks = STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC, + .id = 1, + .irq_base = STMPE811_IRQ_BASE, + .irq_trigger = IRQF_TRIGGER_FALLING, + .ts = &stmpe811_ts_data, + .adc = &stmpe811_adc_data, +}; + +static void lm95245_probe_callback(struct device *dev); + +static struct lm95245_platform_data colibri_t30_lm95245_pdata = { + .enable_os_pin = true, + .probe_callback = lm95245_probe_callback, +}; + +static struct i2c_board_info colibri_t30_i2c_bus5_board_info[] __initdata = { + { + /* SGTL5000 audio codec */ + I2C_BOARD_INFO("sgtl5000", 0x0a), + }, + { + /* STMPE811 touch screen controller */ + I2C_BOARD_INFO("stmpe", 0x41), + .flags = I2C_CLIENT_WAKE, + .platform_data = &stmpe811_data, + .type = "stmpe811", + }, + { + /* LM95245 temperature sensor + Note: OVERT_N directly connected to PMIC PWRDN */ + I2C_BOARD_INFO("lm95245", 0x4c), + .platform_data = &colibri_t30_lm95245_pdata, + }, +}; + +static struct tegra_i2c_platform_data colibri_t30_i2c5_platform_data = { + .adapter_nr = 4, + .arb_recovery = arb_lost_recovery, + .bus_clk_rate = {400000, 0}, + .bus_count = 1, + .scl_gpio = {PWR_I2C_SCL, 0}, + .sda_gpio = {PWR_I2C_SDA, 0}, +}; + +static void __init colibri_t30_i2c_init(void) +{ + tegra_i2c_device1.dev.platform_data = &colibri_t30_i2c1_platform_data; + tegra_i2c_device4.dev.platform_data = &colibri_t30_i2c4_platform_data; + tegra_i2c_device5.dev.platform_data = &colibri_t30_i2c5_platform_data; + + platform_device_register(&tegra_i2c_device1); + platform_device_register(&tegra_i2c_device4); + platform_device_register(&tegra_i2c_device5); + + i2c_register_board_info(0, colibri_t30_i2c_bus1_board_info, + ARRAY_SIZE(colibri_t30_i2c_bus1_board_info)); + + /* enable touch interrupt GPIO */ + gpio_request(TOUCH_PEN_INT, "TOUCH_PEN_INT"); + gpio_direction_input(TOUCH_PEN_INT); + + colibri_t30_i2c_bus5_board_info[1].irq = gpio_to_irq(TOUCH_PEN_INT); + i2c_register_board_info(4, colibri_t30_i2c_bus5_board_info, + ARRAY_SIZE(colibri_t30_i2c_bus5_board_info)); +} + +/* Keys + * Note: active-low means pull-ups required on carrier board resp. via + * pin-muxing + * Note2: power-key active-high due to EvalBoard v3.1a having 100 K pull-down + * on SODIMM pin 45 + * Note3: Wake keys need to be supported by hardware, see wakeups-t3.h + */ + +#ifdef CONFIG_KEYBOARD_GPIO +#define GPIO_KEY(_id, _gpio, _lowactive, _iswake) \ + { \ + .code = _id, \ + .gpio = TEGRA_GPIO_##_gpio, \ + .active_low = _lowactive, \ + .desc = #_id, \ + .type = EV_KEY, \ + .wakeup = _iswake, \ + .debounce_interval = 10, \ + } + +/* Note: Only wake-able gpios can be used as wakeup keys */ +static struct gpio_keys_button colibri_t30_keys[] = { +#ifndef COLIBRI_T30_VI + GPIO_KEY(KEY_FIND, PCC2, 1, 0), /* SODIMM pin 77 */ +#endif + GPIO_KEY(KEY_HOME, PT6, 1, 0), /* SODIMM pin 127 */ + GPIO_KEY(KEY_BACK, PT5, 1, 0), /* SODIMM pin 133, + Iris X16-14 */ + GPIO_KEY(KEY_VOLUMEUP, PDD7, 1, 0), /* SODIMM pin 22 */ + GPIO_KEY(KEY_VOLUMEDOWN, PCC6, 1, 0), /* SODIMM pin 24 */ + GPIO_KEY(KEY_POWER, PV1, 0, 1), /* SODIMM pin 45, + Iris X16-20 */ + GPIO_KEY(KEY_MENU, PK6, 1, 0), /* SODIMM pin 135 */ +}; + +static struct gpio_keys_platform_data colibri_t30_keys_platform_data = { + .buttons = colibri_t30_keys, + .nbuttons = ARRAY_SIZE(colibri_t30_keys), +}; + +static struct platform_device colibri_t30_keys_device = { + .name = "gpio-keys", + .id = 0, + .dev = { + .platform_data = &colibri_t30_keys_platform_data, + }, +}; +#endif /* CONFIG_KEYBOARD_GPIO */ + +/* MMC/SD */ + +#ifndef COLIBRI_T30_SDMMC4B +static struct tegra_sdhci_platform_data colibri_t30_emmc_platform_data = { + .cd_gpio = -1, + .ddr_clk_limit = 52000000, + .is_8bit = 1, + .mmc_data = { + .built_in = 1, + }, + .power_gpio = -1, + .tap_delay = 0x0f, + .wp_gpio = -1, +}; +#endif /* COLIBRI_T30_SDMMC4B */ + +static struct tegra_sdhci_platform_data colibri_t30_sdcard_platform_data = { + .cd_gpio = MMC_CD, + .ddr_clk_limit = 52000000, + .is_8bit = 0, + .power_gpio = -1, + .tap_delay = 0x0f, + .wp_gpio = -1, +}; + +static void __init colibri_t30_sdhci_init(void) +{ + /* register eMMC first */ + tegra_sdhci_device4.dev.platform_data = +#ifdef COLIBRI_T30_SDMMC4B + &colibri_t30_sdcard_platform_data; +#else + &colibri_t30_emmc_platform_data; +#endif + platform_device_register(&tegra_sdhci_device4); + +#ifndef COLIBRI_T30_SDMMC4B + tegra_sdhci_device2.dev.platform_data = + &colibri_t30_sdcard_platform_data; + platform_device_register(&tegra_sdhci_device2); +#endif +} + +/* PWM LEDs */ +static struct led_pwm tegra_leds_pwm[] = { + { + .name = "PWM<B>", + .pwm_id = 1, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, + { + .name = "PWM<C>", + .pwm_id = 2, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, + { + .name = "PWM<D>", + .pwm_id = 3, + .max_brightness = 255, + .pwm_period_ns = 19600, + }, +}; + +static struct led_pwm_platform_data tegra_leds_pwm_data = { + .num_leds = ARRAY_SIZE(tegra_leds_pwm), + .leds = tegra_leds_pwm, +}; + +static struct platform_device tegra_led_pwm_device = { + .name = "leds_pwm", + .id = -1, + .dev = { + .platform_data = &tegra_leds_pwm_data, + }, +}; + +/* RTC */ + +#ifdef CONFIG_RTC_DRV_TEGRA +static struct resource tegra_rtc_resources[] = { + [0] = { + .start = TEGRA_RTC_BASE, + .end = TEGRA_RTC_BASE + TEGRA_RTC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_RTC, + .end = INT_RTC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device tegra_rtc_device = { + .name = "tegra_rtc", + .id = -1, + .resource = tegra_rtc_resources, + .num_resources = ARRAY_SIZE(tegra_rtc_resources), +}; +#endif /* CONFIG_RTC_DRV_TEGRA */ + +/* SPI */ + +#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV) +static struct spi_board_info tegra_spi_devices[] __initdata = { + { + .bus_num = 0, /* SPI1: Colibri SSP */ +#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE) + .chip_select = 0, +#else /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */ + .chip_select = 1, +#endif /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */ + .irq = 0, + .max_speed_hz = 50000000, + .modalias = "spidev", + .mode = SPI_MODE_0, + .platform_data = NULL, + }, +}; + +static void __init colibri_t30_register_spidev(void) +{ + spi_register_board_info(tegra_spi_devices, + ARRAY_SIZE(tegra_spi_devices)); +} +#else /* CONFIG_SPI_TEGRA && CONFIG_SPI_SPIDEV */ +#define colibri_t30_register_spidev() do {} while (0) +#endif /* CONFIG_SPI_TEGRA && CONFIG_SPI_SPIDEV */ + +static struct platform_device *colibri_t30_spi_devices[] __initdata = { + &tegra_spi_device1, +}; + +static struct spi_clk_parent spi_parent_clk[] = { + [0] = {.name = "pll_p"}, +#ifndef CONFIG_TEGRA_PLLM_RESTRICTED + [1] = {.name = "pll_m"}, + [2] = {.name = "clk_m"}, +#else /* !CONFIG_TEGRA_PLLM_RESTRICTED */ + [1] = {.name = "clk_m"}, +#endif /* !CONFIG_TEGRA_PLLM_RESTRICTED */ +}; + +static struct tegra_spi_platform_data colibri_t30_spi_pdata = { + .is_dma_based = true, + .max_dma_buffer = 16 * 1024, + .is_clkon_always = false, + .max_rate = 100000000, +}; + +static void __init colibri_t30_spi_init(void) +{ + int i; + struct clk *c; + + for (i = 0; i < ARRAY_SIZE(spi_parent_clk); ++i) { + c = tegra_get_clock_by_name(spi_parent_clk[i].name); + if (IS_ERR_OR_NULL(c)) { + pr_err("Not able to get the clock for %s\n", + spi_parent_clk[i].name); + continue; + } + spi_parent_clk[i].parent_clk = c; + spi_parent_clk[i].fixed_clk_rate = clk_get_rate(c); + } + colibri_t30_spi_pdata.parent_clk_list = spi_parent_clk; + colibri_t30_spi_pdata.parent_clk_count = ARRAY_SIZE(spi_parent_clk); + tegra_spi_device1.dev.platform_data = &colibri_t30_spi_pdata; + platform_add_devices(colibri_t30_spi_devices, + ARRAY_SIZE(colibri_t30_spi_devices)); +} + +/* Thermal throttling */ + +static void *colibri_t30_alert_data; +static void (*colibri_t30_alert_func)(void *); +static int colibri_t30_low_edge = 0; +static int colibri_t30_low_hysteresis = 3000; +static int colibri_t30_low_limit = 0; +static struct device *lm95245_device = NULL; +static int thermd_alert_irq_disabled = 0; +struct work_struct thermd_alert_work; +struct workqueue_struct *thermd_alert_workqueue; + +static struct balanced_throttle throttle_list[] = { +#ifdef CONFIG_TEGRA_THERMAL_THROTTLE + { + .id = BALANCED_THROTTLE_ID_TJ, + .throt_tab_size = 10, + .throt_tab = { + { 0, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 640000, 1000 }, + { 760000, 1000 }, + { 760000, 1050 }, + {1000000, 1050 }, + {1000000, 1100 }, + }, + }, +#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */ +#ifdef CONFIG_TEGRA_SKIN_THROTTLE + { + .id = BALANCED_THROTTLE_ID_SKIN, + .throt_tab_size = 6, + .throt_tab = { + { 640000, 1200 }, + { 640000, 1200 }, + { 760000, 1200 }, + { 760000, 1200 }, + {1000000, 1200 }, + {1000000, 1200 }, + }, + }, +#endif /* CONFIG_TEGRA_SKIN_THROTTLE */ +}; + +/* All units are in millicelsius */ +static struct tegra_thermal_data thermal_data = { + .shutdown_device_id = THERMAL_DEVICE_ID_NCT_EXT, + .temp_shutdown = 115000, + +#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE) + .throttle_edp_device_id = THERMAL_DEVICE_ID_NCT_EXT, +#endif +#ifdef CONFIG_TEGRA_EDP_LIMITS + .edp_offset = TDIODE_OFFSET, /* edp based on tdiode */ + .hysteresis_edp = 3000, +#endif +#ifdef CONFIG_TEGRA_THERMAL_THROTTLE + .temp_throttle = 85000, + .tc1 = 0, + .tc2 = 1, + .passive_delay = 2000, +#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */ +#ifdef CONFIG_TEGRA_SKIN_THROTTLE + .skin_device_id = THERMAL_DEVICE_ID_SKIN, + .temp_throttle_skin = 43000, + .tc1_skin = 0, + .tc2_skin = 1, + .passive_delay_skin = 5000, + + .skin_temp_offset = 9793, + .skin_period = 1100, + .skin_devs_size = 2, + .skin_devs = { + { + THERMAL_DEVICE_ID_NCT_EXT, + { + 2, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 0, + 1, 1, 0, 0, + 0, 0, -1, -7 + } + }, + { + THERMAL_DEVICE_ID_NCT_INT, + { + -11, -7, -5, -3, + -3, -2, -1, 0, + 0, 0, 1, 1, + 1, 2, 2, 3, + 4, 6, 11, 18 + } + }, + }, +#endif /* CONFIG_TEGRA_SKIN_THROTTLE */ +}; + +/* Over-temperature shutdown OS aka high limit GPIO pin interrupt handler */ +static irqreturn_t thermd_alert_irq(int irq, void *data) +{ + disable_irq_nosync(irq); + thermd_alert_irq_disabled = 1; + queue_work(thermd_alert_workqueue, &thermd_alert_work); + + return IRQ_HANDLED; +} + +/* Gets both entered by THERMD_ALERT GPIO interrupt as well as re-scheduled. */ +static void thermd_alert_work_func(struct work_struct *work) +{ + int temp = 0; + + lm95245_get_remote_temp(lm95245_device, &temp); + + /* This emulates NCT1008 low limit behaviour */ + if (!colibri_t30_low_edge && temp <= colibri_t30_low_limit) { + colibri_t30_alert_func(colibri_t30_alert_data); + colibri_t30_low_edge = 1; + } else if (colibri_t30_low_edge && temp > colibri_t30_low_limit + + colibri_t30_low_hysteresis) { + colibri_t30_low_edge = 0; + } + + /* Avoid unbalanced enable for IRQ 367 */ + if (thermd_alert_irq_disabled) { + colibri_t30_alert_func(colibri_t30_alert_data); + thermd_alert_irq_disabled = 0; + enable_irq(gpio_to_irq(THERMD_ALERT)); + } + + /* Keep re-scheduling */ + msleep(2000); + queue_work(thermd_alert_workqueue, &thermd_alert_work); +} + +static int lm95245_get_temp(void *_data, long *temp) +{ + struct device *lm95245_device = _data; + int lm95245_temp = 0; + lm95245_get_remote_temp(lm95245_device, &lm95245_temp); + *temp = lm95245_temp; + return 0; +} + +static int lm95245_get_temp_low(void *_data, long *temp) +{ + *temp = 0; + return 0; +} + +/* Our temperature sensor only allows triggering an interrupt on over- + temperature shutdown aka the high limit we therefore need to setup a + workqueue to catch leaving the low limit. */ +static int lm95245_set_limits(void *_data, + long lo_limit_milli, + long hi_limit_milli) +{ + struct device *lm95245_device = _data; + colibri_t30_low_limit = lo_limit_milli; + if (lm95245_device) lm95245_set_remote_os_limit(lm95245_device, + hi_limit_milli); + return 0; +} + +static int lm95245_set_alert(void *_data, + void (*alert_func)(void *), + void *alert_data) +{ + lm95245_device = _data; + colibri_t30_alert_func = alert_func; + colibri_t30_alert_data = alert_data; + return 0; +} + +static int lm95245_set_shutdown_temp(void *_data, long shutdown_temp) +{ + struct device *lm95245_device = _data; + if (lm95245_device) lm95245_set_remote_critical_limit(lm95245_device, + shutdown_temp); + return 0; +} + +#ifdef CONFIG_TEGRA_SKIN_THROTTLE +/* Internal aka local board/case temp */ +static int lm95245_get_itemp(void *dev_data, long *temp) +{ + struct device *lm95245_device = dev_data; + int lm95245_temp = 0; + lm95245_get_local_temp(lm95245_device, &lm95245_temp); + *temp = lm95245_temp; + return 0; +} +#endif /* CONFIG_TEGRA_SKIN_THROTTLE */ + +static void lm95245_probe_callback(struct device *dev) +{ + struct tegra_thermal_device *lm95245_remote; + + lm95245_remote = kzalloc(sizeof(struct tegra_thermal_device), + GFP_KERNEL); + if (!lm95245_remote) { + pr_err("unable to allocate thermal device\n"); + return; + } + + lm95245_remote->name = "lm95245_remote"; + lm95245_remote->id = THERMAL_DEVICE_ID_NCT_EXT; + lm95245_remote->data = dev; + lm95245_remote->offset = TDIODE_OFFSET; + lm95245_remote->get_temp = lm95245_get_temp; + lm95245_remote->get_temp_low = lm95245_get_temp_low; + lm95245_remote->set_limits = lm95245_set_limits; + lm95245_remote->set_alert = lm95245_set_alert; + lm95245_remote->set_shutdown_temp = lm95245_set_shutdown_temp; + + tegra_thermal_device_register(lm95245_remote); + +#ifdef CONFIG_TEGRA_SKIN_THROTTLE + { + struct tegra_thermal_device *lm95245_local; + lm95245_local = kzalloc(sizeof(struct tegra_thermal_device), + GFP_KERNEL); + if (!lm95245_local) { + kfree(lm95245_local); + pr_err("unable to allocate thermal device\n"); + return; + } + + lm95245_local->name = "lm95245_local"; + lm95245_local->id = THERMAL_DEVICE_ID_NCT_INT; + lm95245_local->data = dev; + lm95245_local->get_temp = lm95245_get_itemp; + + tegra_thermal_device_register(lm95245_local); + } +#endif /* CONFIG_TEGRA_SKIN_THROTTLE */ + + if (request_irq(gpio_to_irq(THERMD_ALERT), thermd_alert_irq, + IRQF_TRIGGER_LOW, "THERMD_ALERT", NULL)) + pr_err("%s: unable to register THERMD_ALERT interrupt\n", + __func__); + + //initalize the local temp limit + if(dev) + lm95245_set_local_shared_os__critical_limit(dev, TCRIT_LOCAL); +} + +static void colibri_t30_thermd_alert_init(void) +{ + gpio_request(THERMD_ALERT, "THERMD_ALERT"); + gpio_direction_input(THERMD_ALERT); + + thermd_alert_workqueue = create_singlethread_workqueue("THERMD_ALERT"); + + INIT_WORK(&thermd_alert_work, thermd_alert_work_func); +} + +/* UART */ + +static struct platform_device *colibri_t30_uart_devices[] __initdata = { + &tegra_uarta_device, /* Colibri FFUART */ + &tegra_uartd_device, /* Colibri BTUART */ + &tegra_uartb_device, /* Colibri STDUART */ +}; + +static struct uart_clk_parent uart_parent_clk[] = { + [0] = {.name = "clk_m"}, + [1] = {.name = "pll_p"}, +#ifndef CONFIG_TEGRA_PLLM_RESTRICTED + [2] = {.name = "pll_m"}, +#endif +}; + +static struct tegra_uart_platform_data colibri_t30_uart_pdata; + +static void __init uart_debug_init(void) +{ + int debug_port_id; + + debug_port_id = get_tegra_uart_debug_port_id(); + if (debug_port_id < 0) { + debug_port_id = 0; + } + + switch (debug_port_id) { + case 0: + /* UARTA is the debug port. */ + pr_info("Selecting UARTA as the debug console\n"); + colibri_t30_uart_devices[0] = &debug_uarta_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uarta"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uarta_device.dev.platform_data))->mapbase; + break; + + case 1: + /* UARTB is the debug port. */ + pr_info("Selecting UARTB as the debug console\n"); + colibri_t30_uart_devices[2] = &debug_uartb_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uartb"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uartb_device.dev.platform_data))->mapbase; + break; + + case 3: + /* UARTD is the debug port. */ + pr_info("Selecting UARTD as the debug console\n"); + colibri_t30_uart_devices[1] = &debug_uartd_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uartd"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uartd_device.dev.platform_data))->mapbase; + break; + + default: + pr_info("The debug console id %d is invalid, Assuming UARTA", + debug_port_id); + colibri_t30_uart_devices[0] = &debug_uarta_device; + debug_uart_clk = clk_get_sys("serial8250.0", "uarta"); + debug_uart_port_base = ((struct plat_serial8250_port *)( + debug_uarta_device.dev.platform_data))->mapbase; + break; + } + return; +} + +static void __init colibri_t30_uart_init(void) +{ + struct clk *c; + int i; + + for (i = 0; i < ARRAY_SIZE(uart_parent_clk); ++i) { + c = tegra_get_clock_by_name(uart_parent_clk[i].name); + if (IS_ERR_OR_NULL(c)) { + pr_err("Not able to get the clock for %s\n", + uart_parent_clk[i].name); + continue; + } + uart_parent_clk[i].parent_clk = c; + uart_parent_clk[i].fixed_clk_rate = clk_get_rate(c); + } + colibri_t30_uart_pdata.parent_clk_list = uart_parent_clk; + colibri_t30_uart_pdata.parent_clk_count = ARRAY_SIZE(uart_parent_clk); + tegra_uarta_device.dev.platform_data = &colibri_t30_uart_pdata; + tegra_uartb_device.dev.platform_data = &colibri_t30_uart_pdata; + tegra_uartd_device.dev.platform_data = &colibri_t30_uart_pdata; + + /* Register low speed only if it is selected */ + if (!is_tegra_debug_uartport_hs()) { + uart_debug_init(); + /* Clock enable for the debug channel */ + if (!IS_ERR_OR_NULL(debug_uart_clk)) { + pr_info("The debug console clock name is %s\n", + debug_uart_clk->name); + c = tegra_get_clock_by_name("pll_p"); + if (IS_ERR_OR_NULL(c)) + pr_err("Not getting the parent clock pll_p\n"); + else + clk_set_parent(debug_uart_clk, c); + + clk_enable(debug_uart_clk); + clk_set_rate(debug_uart_clk, clk_get_rate(c)); + } else { + pr_err("Not getting the clock %s for debug console\n", + debug_uart_clk->name); + } + } + + platform_add_devices(colibri_t30_uart_devices, + ARRAY_SIZE(colibri_t30_uart_devices)); +} + +/* USB */ + +//TODO: overcurrent + +static struct tegra_usb_platform_data tegra_udc_pdata = { + .has_hostpc = true, + .op_mode = TEGRA_USB_OPMODE_DEVICE, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = true, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 8, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.dev = { + .charging_supported = false, + .remote_wakeup_supported = false, + .vbus_gpio = -1, + .vbus_pmu_irq = 0, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = { + .has_hostpc = true, + .op_mode = TEGRA_USB_OPMODE_HOST, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = true, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 15, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.host = { + .hot_plug = true, + .power_off_on_suspend = false, + .remote_wakeup_supported = true, + .vbus_gpio = -1, + .vbus_reg = NULL, + }, +}; + +static void ehci2_utmi_platform_post_phy_on(void) +{ + /* enable VBUS */ + gpio_set_value(LAN_V_BUS, 1); + + /* reset */ + gpio_set_value(LAN_RESET, 0); + + udelay(5); + + /* unreset */ + gpio_set_value(LAN_RESET, 1); +} + +static void ehci2_utmi_platform_pre_phy_off(void) +{ + /* disable VBUS */ + gpio_set_value(LAN_V_BUS, 0); +} + +static struct tegra_usb_phy_platform_ops ehci2_utmi_plat_ops = { + .post_phy_on = ehci2_utmi_platform_post_phy_on, + .pre_phy_off = ehci2_utmi_platform_pre_phy_off, +}; + +static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = { + .has_hostpc = true, + .op_mode = TEGRA_USB_OPMODE_HOST, + .ops = &ehci2_utmi_plat_ops, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = false, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 15, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.host = { + .hot_plug = false, + .power_off_on_suspend = true, + .remote_wakeup_supported = true, + .vbus_gpio = -1, + .vbus_reg = NULL, + }, +}; + +static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = { + .has_hostpc = true, + .op_mode = TEGRA_USB_OPMODE_HOST, + .phy_intf = TEGRA_USB_PHY_INTF_UTMI, + .port_otg = false, + .u_cfg.utmi = { + .elastic_limit = 16, + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .term_range_adj = 6, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + .xcvr_setup = 8, + .xcvr_setup_offset = 0, + .xcvr_use_fuses = 1, + }, + .u_data.host = { + .hot_plug = true, + .power_off_on_suspend = false, + .remote_wakeup_supported = true, + .vbus_gpio = USBH_PEN, + .vbus_gpio_inverted = 1, + .vbus_reg = NULL, + }, +}; + +#ifndef CONFIG_USB_TEGRA_OTG +static struct platform_device *tegra_usb_otg_host_register(void) +{ + struct platform_device *pdev; + void *platform_data; + int val; + + pdev = platform_device_alloc(tegra_ehci1_device.name, + tegra_ehci1_device.id); + if (!pdev) + return NULL; + + val = platform_device_add_resources(pdev, tegra_ehci1_device.resource, + tegra_ehci1_device.num_resources); + if (val) + goto error; + + pdev->dev.dma_mask = tegra_ehci1_device.dev.dma_mask; + pdev->dev.coherent_dma_mask = tegra_ehci1_device.dev.coherent_dma_mask; + + platform_data = kmalloc(sizeof(struct tegra_usb_platform_data), + GFP_KERNEL); + if (!platform_data) + goto error; + + memcpy(platform_data, &tegra_ehci1_utmi_pdata, + sizeof(struct tegra_usb_platform_data)); + pdev->dev.platform_data = platform_data; + + val = platform_device_add(pdev); + if (val) + goto error_add; + + return pdev; + +error_add: + kfree(platform_data); +error: + pr_err("%s: failed to add the host controller device\n", __func__); + platform_device_put(pdev); + return NULL; +} + +static void tegra_usb_otg_host_unregister(struct platform_device *pdev) +{ + platform_device_unregister(pdev); +} + +static struct colibri_otg_platform_data colibri_otg_pdata = { + .cable_detect_gpio = USBC_DET, + .host_register = &tegra_usb_otg_host_register, + .host_unregister = &tegra_usb_otg_host_unregister, +}; +#else /* !CONFIG_USB_TEGRA_OTG */ +static struct tegra_usb_otg_data tegra_otg_pdata = { + .ehci_device = &tegra_ehci1_device, + .ehci_pdata = &tegra_ehci1_utmi_pdata, +}; +#endif /* !CONFIG_USB_TEGRA_OTG */ + +#ifndef CONFIG_USB_TEGRA_OTG +struct platform_device colibri_otg_device = { + .name = "colibri-otg", + .id = -1, + .dev = { + .platform_data = &colibri_otg_pdata, + }, +}; +#endif /* !CONFIG_USB_TEGRA_OTG */ + +static void colibri_t30_usb_init(void) +{ + gpio_request(LAN_V_BUS, "LAN_V_BUS"); + gpio_direction_output(LAN_V_BUS, 0); + gpio_export(LAN_V_BUS, false); + + gpio_request(LAN_RESET, "LAN_RESET"); + gpio_direction_output(LAN_RESET, 0); + gpio_export(LAN_RESET, false); + + /* OTG should be the first to be registered + EHCI instance 0: USB1_DP/N -> USBOTG_P/N */ +#ifndef CONFIG_USB_TEGRA_OTG + platform_device_register(&colibri_otg_device); +#else /* !CONFIG_USB_TEGRA_OTG */ + tegra_otg_device.dev.platform_data = &tegra_otg_pdata; + platform_device_register(&tegra_otg_device); +#endif /* !CONFIG_USB_TEGRA_OTG */ + + /* setup the udc platform data */ + tegra_udc_device.dev.platform_data = &tegra_udc_pdata; + platform_device_register(&tegra_udc_device); + + /* EHCI instance 1: ASIX ETH */ + tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata; + platform_device_register(&tegra_ehci2_device); + + /* EHCI instance 2: USB3_DP/N -> USBH1_P/N */ + tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata; + platform_device_register(&tegra_ehci3_device); +} + +/* W1, aka OWR, aka OneWire */ + +#ifdef CONFIG_W1_MASTER_TEGRA +struct tegra_w1_timings colibri_t30_w1_timings = { + .tsu = 1, + .trelease = 0xf, + .trdv = 0xf, + .tlow0 = 0x3c, + .tlow1 = 1, + .tslot = 0x77, + + .tpdl = 0x78, + .tpdh = 0x1e, + .trstl = 0x1df, + .trsth = 0x1df, + .rdsclk = 0x7, + .psclk = 0x50, +}; + +struct tegra_w1_platform_data colibri_t30_w1_platform_data = { + .clk_id = "tegra_w1", + .timings = &colibri_t30_w1_timings, +}; +#endif /* CONFIG_W1_MASTER_TEGRA */ + +static struct platform_device *colibri_t30_devices[] __initdata = { + &tegra_pmu_device, +#if defined(CONFIG_RTC_DRV_TEGRA) + &tegra_rtc_device, +#endif +#if defined(CONFIG_TEGRA_IOVMM_SMMU) || defined(CONFIG_TEGRA_IOMMU_SMMU) + &tegra_smmu_device, +#endif + &tegra_wdt0_device, + &tegra_wdt1_device, + &tegra_wdt2_device, +#if defined(CONFIG_TEGRA_AVP) + &tegra_avp_device, +#endif +#ifdef CONFIG_TEGRA_CAMERA + &tegra_camera, +#endif +#if defined(CONFIG_CRYPTO_DEV_TEGRA_SE) + &tegra_se_device, +#endif +#if defined(CONFIG_CRYPTO_DEV_TEGRA_AES) + &tegra_aes_device, +#endif + &tegra_ahub_device, + &tegra_dam_device0, + &tegra_dam_device1, + &tegra_dam_device2, + &tegra_i2s_device2, + &tegra_spdif_device, + &spdif_dit_device, + &tegra_pcm_device, + &colibri_t30_audio_sgtl5000_device, +#ifdef CONFIG_ANDROID + &tegra_hda_device, +#endif + &tegra_cec_device, +#ifdef CONFIG_KEYBOARD_GPIO + &colibri_t30_keys_device, +#endif + &tegra_led_pwm_device, + &tegra_pwfm1_device, + &tegra_pwfm2_device, + &tegra_pwfm3_device, +#ifdef CONFIG_W1_MASTER_TEGRA + &tegra_w1_device, +#endif +}; + +static void __init colibri_t30_init(void) +{ + tegra_thermal_init(&thermal_data, + throttle_list, + ARRAY_SIZE(throttle_list)); + tegra_clk_init_from_table(colibri_t30_clk_init_table); + colibri_t30_pinmux_init(); +#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE) + writel(TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG); + writel(TEGRA_SNOR_CONFIG_GO | TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG); + colibri_can_resource[1].start = gpio_to_irq(TEGRA_GPIO_PS0); + colibri_can_resource[1].end = gpio_to_irq(TEGRA_GPIO_PS0); + platform_device_register(&colibri_can_device); +#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */ + colibri_t30_thermd_alert_init(); + colibri_t30_i2c_init(); + colibri_t30_spi_init(); + colibri_t30_usb_init(); +#ifdef CONFIG_TEGRA_EDP_LIMITS + colibri_t30_edp_init(); +#endif + colibri_t30_uart_init(); +#ifdef CONFIG_W1_MASTER_TEGRA + tegra_w1_device.dev.platform_data = &colibri_t30_w1_platform_data; +#endif + platform_add_devices(colibri_t30_devices, ARRAY_SIZE(colibri_t30_devices)); + tegra_ram_console_debug_init(); + tegra_io_dpd_init(); + colibri_t30_sdhci_init(); + colibri_t30_regulator_init(); + colibri_t30_suspend_init(); + colibri_t30_panel_init(); +// colibri_t30_sensors_init(); + colibri_t30_emc_init(); + colibri_t30_register_spidev(); + colibri_t20_mcp2515_can_init(); + colibri_t30_gpio_init(); + +#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE) + t30_get_tegra_vi01_device()->dev.platform_data = &tegra_camera_platform_data; +#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE) + platform_device_register(&soc_camera_max9526); +#endif +#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE) + platform_device_register(&soc_camera_adv7180); +#endif +#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */ + + tegra_release_bootloader_fb(); +#ifdef CONFIG_TEGRA_WDT_RECOVERY + tegra_wdt_recovery_init(); +#endif + tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1); + + /* Activate Mic Bias */ + gpio_request(EN_MIC_GND, "EN_MIC_GND"); + gpio_direction_output(EN_MIC_GND, 1); +} + +static void __init colibri_t30_reserve(void) +{ +#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM) + /* Support 1920X1080 32bpp,double buffered on HDMI*/ + tegra_reserve(0, SZ_8M + SZ_1M, SZ_16M); +#else + tegra_reserve(SZ_128M, SZ_8M, SZ_8M); +#endif + tegra_ram_console_debug_reserve(SZ_1M); +} + +static const char *colibri_t30_dt_board_compat[] = { + "toradex,colibri_t30", + NULL +}; + +#ifdef CONFIG_ANDROID +MACHINE_START(COLIBRI_T30, "cardhu") +#else +MACHINE_START(COLIBRI_T30, "Toradex Colibri T30") +#endif + .boot_params = 0x80000100, + .dt_compat = colibri_t30_dt_board_compat, + .init_early = tegra_init_early, + .init_irq = tegra_init_irq, + .init_machine = colibri_t30_init, + .map_io = tegra_map_common_io, + .reserve = colibri_t30_reserve, + .timer = &tegra_timer, +MACHINE_END diff --git a/arch/arm/mach-tegra/board-colibri_t30.h b/arch/arm/mach-tegra/board-colibri_t30.h new file mode 100644 index 000000000000..3c67cb10f960 --- /dev/null +++ b/arch/arm/mach-tegra/board-colibri_t30.h @@ -0,0 +1,115 @@ +/* + * arch/arm/mach-tegra/board-colibri_t30.h + * + * Copyright (c) 2012 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MACH_TEGRA_BOARD_COLIBRI_T30_H +#define _MACH_TEGRA_BOARD_COLIBRI_T30_H + +#include <linux/mfd/tps6591x.h> + +#include <mach/gpio.h> +#include <mach/irqs.h> + +/* Uncomment for camera interface support on Colibri Evaluation carrier + board */ +#if defined(CONFIG_TEGRA_CAMERA) || defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE) +#define COLIBRI_T30_VI +#endif + +/* GPIO */ + +#define DDC_SCL TEGRA_GPIO_PV4 /* X2-15 */ +#define DDC_SDA TEGRA_GPIO_PV5 /* X2-16 */ + +#ifdef COLIBRI_T30_V10 +#define EMMC_DETECT TEGRA_GPIO_PC7 +#endif + +#define EN_MIC_GND TEGRA_GPIO_PT1 + +#define I2C_SCL TEGRA_GPIO_PC4 /* SODIMM 196 */ +#define I2C_SDA TEGRA_GPIO_PC5 /* SODIMM 194 */ + +#define LAN_EXT_WAKEUP TEGRA_GPIO_PDD1 +#define LAN_PME TEGRA_GPIO_PDD3 +#define LAN_RESET TEGRA_GPIO_PDD0 +#define LAN_V_BUS TEGRA_GPIO_PDD2 + +#ifdef COLIBRI_T30_V10 +#define MMC_CD TEGRA_GPIO_PU6 /* SODIMM 43 */ +#else +#define MMC_CD TEGRA_GPIO_PC7 /* SODIMM 43 */ +#endif + +#define PWR_I2C_SCL TEGRA_GPIO_PZ6 +#define PWR_I2C_SDA TEGRA_GPIO_PZ7 + +#define THERMD_ALERT TEGRA_GPIO_PD2 + +#define TOUCH_PEN_INT TEGRA_GPIO_PV0 + +#define USBC_DET TEGRA_GPIO_PK5 /* SODIMM 137 */ +#define USBH_OC TEGRA_GPIO_PW3 /* SODIMM 131 */ +#define USBH_PEN TEGRA_GPIO_PW2 /* SODIMM 129 */ + +/* Uncomment for Colibri T30 V1.0a prototypes */ +//#define COLIBRI_T30_V10 + +/* Uncomment for SD-card on SDMMC4B rather than SDMMC2 */ +//#define COLIBRI_T30_SDMMC4B + +/* STMPE811 IRQs */ +#define STMPE811_IRQ_BASE TEGRA_NR_IRQS +#define STMPE811_IRQ_END (STMPE811_IRQ_BASE + 22) + +#define TDIODE_OFFSET (10000) /* in millicelsius */ +#define TCRIT_LOCAL 95000 /* board temperature which switches off PMIC in millicelsius*/ + +/* External peripheral act as gpio */ +/* TPS6591x GPIOs */ +#define TPS6591X_GPIO_BASE TEGRA_NR_GPIOS +#define TPS6591X_GPIO_0 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP0) +#define TPS6591X_GPIO_1 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP1) +#define TPS6591X_GPIO_2 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP2) +#define TPS6591X_GPIO_3 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP3) +#define TPS6591X_GPIO_4 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP4) +#define TPS6591X_GPIO_5 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP5) +#define TPS6591X_GPIO_6 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP6) +#define TPS6591X_GPIO_7 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP7) +#define TPS6591X_GPIO_8 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP8) +#define TPS6591X_GPIO_END (TPS6591X_GPIO_BASE + TPS6591X_GPIO_NR) + +/*****************Interrupt tables ******************/ +/* External peripheral act as interrupt controller */ +/* TPS6591x IRQs */ +#define TPS6591X_IRQ_BASE STMPE811_IRQ_END +#define TPS6591X_IRQ_END (TPS6591X_IRQ_BASE + 18) + +int colibri_t30_regulator_init(void); +int colibri_t30_suspend_init(void); +int colibri_t30_pinmux_init(void); +int colibri_t30_panel_init(void); +int colibri_t30_sensors_init(void); +int colibri_t30_gpio_switch_regulator_init(void); +int colibri_t30_pins_state_init(void); +int colibri_t30_emc_init(void); +int colibri_t30_power_off_init(void); +int colibri_t30_edp_init(void); + +#endif diff --git a/arch/arm/mach-tegra/board-e1853.h b/arch/arm/mach-tegra/board-e1853.h index 58b8ab8725af..ebd8c1b0b576 100644 --- a/arch/arm/mach-tegra/board-e1853.h +++ b/arch/arm/mach-tegra/board-e1853.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/e1853/board-e1853.h + * arch/arm/mach-tegra/board-e1853.h * * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * diff --git a/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c b/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c index 718047acf896..5c5cb9b1bae0 100644 --- a/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c +++ b/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-touch-synaptics-spi.c + * arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c * * Copyright (C) 2010-2012 NVIDIA Corporation * diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index 035a41c99359..703393ba7bd9 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/clock.h + * arch/arm/mach-tegra/clock.h * * Copyright (C) 2010 Google, Inc. * @@ -25,7 +25,12 @@ #ifdef CONFIG_ARCH_TEGRA_2x_SOC #define USE_PLL_LOCK_BITS 0 /* Never use lock bits on Tegra2 */ #else -#define USE_PLL_LOCK_BITS 1 /* Use lock bits for PLL stabiliation */ +#if defined(CONFIG_MACH_APALIS_T30) || defined(CONFIG_MACH_COLIBRI_T30) +/* Hack: avoid lock-up during boot-up due to missing pll_a lock bit. */ +#define USE_PLL_LOCK_BITS 0 /* Never use lock bits on Apalis/Colibri T30 */ +#else /* CONFIG_MACH_APALIS_T30 | CONFIG_MACH_COLIBRI_T30 */ +#define USE_PLL_LOCK_BITS 1 /* Use lock bits for PLL stabilisation */ +#endif /* CONFIG_MACH_APALIS_T30 | CONFIG_MACH_COLIBRI_T30 */ #define USE_PLLE_SS 1 /* Use spread spectrum coefficients for PLLE */ #define PLL_POST_LOCK_DELAY 50 /* Safety delay after lock is detected */ #endif diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 0d1407b6b668..d5acd8bdea76 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -172,6 +172,9 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = { { "pll_p_out4", "pll_p", 108000000, false }, { "pll_m", "clk_m", 0, true }, { "pll_m_out1", "pll_m", 120000000, true }, +//[ 0.000000] Failed to set parent pll_c_out1 for sclk (violates clock limit 240000000) +//[ 0.000000] Unable to set parent pll_c_out1 of clock sclk: -22 + { "pll_c_out1", "pll_c", 40000000, false }, { "sclk", "pll_c_out1", 40000000, true }, { "hclk", "sclk", 40000000, true }, { "pclk", "hclk", 40000000, true }, @@ -466,6 +469,21 @@ static int __init tegra_lp0_vec_arg(char *options) } early_param("lp0_vec", tegra_lp0_vec_arg); +static int __init tegra_bootloader_fb_arg0(char *options) +{ + char *p = options; + + tegra_bootloader_fb_size = memparse(p, &p); + if (*p == '@') + tegra_bootloader_fb_start = memparse(p+1, &p); + + pr_info("Found fbmem: %08lx@%08lx\n", + tegra_bootloader_fb_size, tegra_bootloader_fb_start); + + return 0; +} +early_param("fbmem", tegra_bootloader_fb_arg0); + static int __init tegra_bootloader_fb_arg(char *options) { char *p = options; @@ -496,6 +514,27 @@ static int __init tegra_bootloader_fb2_arg(char *options) } early_param("tegra_fbmem2", tegra_bootloader_fb2_arg); +/* To specify NVIDIA carveout memory */ +static int __init parse_nvmem(char *p) +{ + unsigned long size, start; + char *endp; + + size = memparse(p, &endp); + if (*endp == '@') { + start = memparse(endp + 1, NULL); + if (start && size) { + pr_info("Found nvmem: %08lx@%08lx\n", size, start); + tegra_carveout_start = start; + tegra_carveout_size = size; + return 0; + } + } + + return -EINVAL; +} +early_param("nvmem", parse_nvmem); + static int __init tegra_sku_override(char *id) { char *p = id; @@ -892,6 +931,9 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size, tegra_carveout_size = 0; } else tegra_carveout_size = carveout_size; + } else { + /* special handling due to already reserved fbmem/nvmem */ + fb2_size -= tegra_bootloader_fb_size; } if (fb2_size) { @@ -906,6 +948,11 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size, tegra_fb2_size = fb2_size; } + if (!carveout_size) { + /* special handling due to already reserved fbmem/nvmem */ + tegra_fb2_size += tegra_bootloader_fb_size; + } + if (fb_size) { tegra_fb_start = memblock_end_of_DRAM() - fb_size; if (memblock_remove(tegra_fb_start, fb_size)) { diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c index 508320582560..c3bc1ded475a 100644 --- a/arch/arm/mach-tegra/devices.c +++ b/arch/arm/mach-tegra/devices.c @@ -886,6 +886,31 @@ struct platform_device debug_uarte_device = { #endif #ifdef CONFIG_ARCH_TEGRA_2x_SOC +static struct resource tegra_ac97_resource[] = { + [0] = { + .start = INT_AC97, + .end = INT_AC97, + .flags = IORESOURCE_IRQ + }, + [1] = { + .start = TEGRA_DMA_REQ_SEL_AC97, + .end = TEGRA_DMA_REQ_SEL_AC97, + .flags = IORESOURCE_DMA + }, + [2] = { + .start = TEGRA_AC97_BASE, + .end = TEGRA_AC97_BASE + TEGRA_AC97_SIZE - 1, + .flags = IORESOURCE_MEM + } +}; + +struct platform_device tegra_ac97_device = { + .name = "tegra20-ac97", + .id = -1, + .resource = tegra_ac97_resource, + .num_resources = ARRAY_SIZE(tegra_ac97_resource), +}; + static struct resource i2s_resource1[] = { [0] = { .start = INT_I2S1, diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h index ca492cdd11db..02962b59031f 100644 --- a/arch/arm/mach-tegra/devices.h +++ b/arch/arm/mach-tegra/devices.h @@ -75,6 +75,7 @@ extern struct platform_device tegra_udc_device; extern struct platform_device tegra_ehci1_device; extern struct platform_device tegra_ehci2_device; extern struct platform_device tegra_ehci3_device; +extern struct platform_device tegra_ac97_device; extern struct platform_device tegra_i2s_device1; extern struct platform_device tegra_i2s_device2; #ifndef CONFIG_ARCH_TEGRA_2x_SOC diff --git a/arch/arm/mach-tegra/gic.h b/arch/arm/mach-tegra/gic.h index 22bb85f18525..bd5423ea1235 100644 --- a/arch/arm/mach-tegra/gic.h +++ b/arch/arm/mach-tegra/gic.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/gic.h + * arch/arm/mach-tegra/gic.h * * Copyright (C) 2010-2012 NVIDIA Corporation * diff --git a/arch/arm/mach-tegra/gpio-names.h b/arch/arm/mach-tegra/gpio-names.h index cb3c5ce29c0f..b1adddf12388 100644 --- a/arch/arm/mach-tegra/gpio-names.h +++ b/arch/arm/mach-tegra/gpio-names.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/gpio-names.h + * arch/arm/mach-tegra/gpio-names.h * * Copyright (c) 2010 Google, Inc * Copyright (C) 2011 NVIDIA Corporation. diff --git a/arch/arm/mach-tegra/include/mach/ac97.h b/arch/arm/mach-tegra/include/mach/ac97.h new file mode 100644 index 000000000000..a62cb93123a9 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/ac97.h @@ -0,0 +1,87 @@ +/* + * arch/arm/mach-tegra/include/mach/ac97.h + * + * Copyright (C) 2011 Toradex, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __ARCH_ARM_MACH_TEGRA_AC97_H +#define __ARCH_ARM_MACH_TEGRA_AC97_H + +#include <linux/kernel.h> +#include <linux/types.h> + +/* Offsets from TEGRA_AC97_BASE */ +#define AC_AC_CTRL_0 0 +#define AC_AC_CMD_0 4 +#define AC_AC_STATUS1_0 8 +/* ... */ +#define AC_AC_FIFO1_SCR_0 0x1c +#define AC_AC_FIFO2_SCR_0 0x2c +/* ... */ +#define AC_AC_FIFO_OUT1_0 0x40 +#define AC_AC_FIFO_IN1_0 0x80 +#define AC_AC_FIFO_OUT2_0 0x140 +#define AC_AC_FIFO_IN2_0 0x180 + +/* AC_AC_CTRL_0 */ +#define AC_AC_CTRL_STM2_EN (1<<16) +#define AC_AC_CTRL_DOUBLE_SAMPLING_EN (1<<11) +#define AC_AC_CTRL_IO_CNTRL_EN (1<<10) +#define AC_AC_CTRL_HSET_DAC_EN (1<<9) +#define AC_AC_CTRL_LINE2_DAC_EN (1<<8) +#define AC_AC_CTRL_PCM_LFE_EN (1<<7) +#define AC_AC_CTRL_PCM_SUR_EN (1<<6) +#define AC_AC_CTRL_PCM_CEN_DAC_EN (1<<5) +#define AC_AC_CTRL_LINE1_DAC_EN (1<<4) +#define AC_AC_CTRL_PCM_DAC_EN (1<<3) +#define AC_AC_CTRL_COLD_RESET (1<<2) +#define AC_AC_CTRL_WARM_RESET (1<<1) +#define AC_AC_CTRL_STM_EN (1<<0) + +/* AC_AC_CMD_0 */ +#define AC_AC_CMD_CMD_ADDR_SHIFT (24) +#define AC_AC_CMD_CMD_ADDR_MASK (0xff<<AC_AC_CMD_CMD_ADDR_SHIFT) +#define AC_AC_CMD_CMD_DATA_SHIFT (8) +#define AC_AC_CMD_CMD_DATA_MASK (0xffff<<AC_AC_CMD_CMD_DATA_SHIFT) +#define AC_AC_CMD_CMD_ID_SHIFT (2) +#define AC_AC_CMD_CMD_ID_MASK (0x3<<AC_AC_CMD_CMD_ID_SHIFT) +#define AC_AC_CMD_BUSY (1<<0) + +/* AC_AC_STATUS1_0 */ +#define AC_AC_STATUS1_STA_ADDR1_SHIFT (24) +#define AC_AC_STATUS1_STA_ADDR1_MASK (0xff<<AC_AC_STATUS1_STA_ADDR1_SHIFT) +#define AC_AC_STATUS1_STA_DATA1_SHIFT (8) +#define AC_AC_STATUS1_STA_DATA1_MASK (0xffff<<AC_AC_STATUS1_STA_DATA1_SHIFT) +#define AC_AC_STATUS1_STA_VALID1 (1<<2) +#define AC_AC_STATUS1_STANDBY1 (1<<1) +#define AC_AC_STATUS1_CODEC1_RDY (1<<0) + +/* AC_AC_FIFO1_SCR_0 and AC_AC_FIFO2_SCR_0 */ +#define AC_AC_FIFOx_SCR_REC_FIFOx_MT_CNT_SHIFT (27) +#define AC_AC_FIFOx_SCR_REC_FIFOx_MT_CNT_MASK (0x1f << REC_FIFO1_MT_CNT_SHIFT) +#define AC_AC_FIFOx_SCR_PB_FIFOx_MT_CNT_SHIFT (22) +#define AC_AC_FIFOx_SCR_PB_FIFOx_MT_CNT_MASK (0x1f << PB_FIFO1_MT_CNT_SHIFT) +#define AC_AC_FIFOx_SCR_REC_FIFOx_OVERRUN_INT_STA (1<<19) +#define AC_AC_FIFOx_SCR_PB_FIFOx_UNDERRUN_INT_STA (1<<18) +#define AC_AC_FIFOx_SCR_RECx_FORCE_MT (1<<17) +#define AC_AC_FIFOx_SCR_PBx_FORCE_MT (1<<16) +#define AC_AC_FIFOx_SCR_REC_FIFOx_FULL_EN (1<<15) +#define AC_AC_FIFOx_SCR_REC_FIFOx_3QRT_FULL_EN (1<<14) +#define AC_AC_FIFOx_SCR_REC_FIFOx_QRT_FULL_EN (1<<13) +#define AC_AC_FIFOx_SCR_REC_FIFOx_NOT_MT_EN (1<<12) +#define AC_AC_FIFOx_SCR_PB_FIFOx_NOT_FULL_EN (1<<11) +#define AC_AC_FIFOx_SCR_PB_FIFOx_QRT_MT_EN (1<<10) +#define AC_AC_FIFOx_SCR_PB_FIFOx_3QRT_MT_EN (1<<9) +#define AC_AC_FIFOx_SCR_PB_FIFOx_MT_EN (1<<8) + +#endif /* __ARCH_ARM_MACH_TEGRA_AC97_H */ diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index d7aaed0bdcdc..a60e3e5b14fa 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -353,6 +353,8 @@ struct tegra_dc_out { unsigned depth; unsigned dither; + char *default_mode; + struct tegra_dc_mode *modes; int n_modes; @@ -544,10 +546,14 @@ void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val); */ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n); int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n); +#ifndef CONFIG_ANDROID int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable); bool tegra_dc_is_within_n_vsync(struct tegra_dc *dc, s64 ts); bool tegra_dc_does_vsync_separate(struct tegra_dc *dc, s64 new_ts, s64 old_ts); +#endif /* !CONFIG_ANDROID */ +int tegra_dc_var_to_dc_mode(struct tegra_dc *dc, struct fb_var_screeninfo *var, + struct tegra_dc_mode *mode); int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode); struct fb_videomode; int tegra_dc_set_fb_mode(struct tegra_dc *dc, const struct fb_videomode *fbmode, @@ -592,8 +598,9 @@ struct tegra_dc_edid { struct tegra_dc_edid *tegra_dc_get_edid(struct tegra_dc *dc); void tegra_dc_put_edid(struct tegra_dc_edid *edid); -int tegra_dc_set_flip_callback(void (*callback)(void)); +int tegra_dc_set_flip_callback(int (*callback)(void)); int tegra_dc_unset_flip_callback(void); int tegra_dc_get_panel_sync_rate(void); - +int tegra_fb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, + const char* option, unsigned int default_bpp); #endif diff --git a/arch/arm/mach-tegra/include/mach/kfuse.h b/arch/arm/mach-tegra/include/mach/kfuse.h index cfe85cc86ff2..b9262a3d6d0f 100644 --- a/arch/arm/mach-tegra/include/mach/kfuse.h +++ b/arch/arm/mach-tegra/include/mach/kfuse.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/kfuse.h + * arch/arm/mach-tegra/include/mach/kfuse.h * * Copyright (C) 2010-2011 NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h b/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h index 210b9f61ecb5..98abc9a35e3e 100644 --- a/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h +++ b/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.c + * arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h * * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. * diff --git a/arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h b/arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h index 944e410b4aec..50e5cc804893 100644 --- a/arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h +++ b/arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h + * arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h * * Copyright 2011 NVIDIA, Inc. * diff --git a/arch/arm/mach-tegra/include/mach/thermal.h b/arch/arm/mach-tegra/include/mach/thermal.h index ed71d0340a96..12262685d7cd 100644 --- a/arch/arm/mach-tegra/include/mach/thermal.h +++ b/arch/arm/mach-tegra/include/mach/thermal.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/thermal.h + * arch/arm/mach-tegra/include/mach/thermal.h * * Copyright (C) 2010-2012 NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-gpio.c b/arch/arm/mach-tegra/p852/board-p852-gpio.c index 6272d36fb849..c92ca8dd2423 100644 --- a/arch/arm/mach-tegra/p852/board-p852-gpio.c +++ b/arch/arm/mach-tegra/p852/board-p852-gpio.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-gpio.c + * arch/arm/mach-tegra/p852/board-p852-gpio.c * * Copyright (C) 2010-2011 NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-i2c.c b/arch/arm/mach-tegra/p852/board-p852-i2c.c index 041ec252b6c1..0d197e04852f 100644 --- a/arch/arm/mach-tegra/p852/board-p852-i2c.c +++ b/arch/arm/mach-tegra/p852/board-p852-i2c.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-i2c.c + * arch/arm/mach-tegra/p852/board-p852-i2c.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-panel.c b/arch/arm/mach-tegra/p852/board-p852-panel.c index 8ed62f039dc8..579632081344 100644 --- a/arch/arm/mach-tegra/p852/board-p852-panel.c +++ b/arch/arm/mach-tegra/p852/board-p852-panel.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-panel.c + * arch/arm/mach-tegra/p852/board-p852-panel.c * * Copyright (c) 2010-2012, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-pinmux.c b/arch/arm/mach-tegra/p852/board-p852-pinmux.c index 0ded989f7a13..d00f23d3c32b 100644 --- a/arch/arm/mach-tegra/p852/board-p852-pinmux.c +++ b/arch/arm/mach-tegra/p852/board-p852-pinmux.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-pinmux.c + * arch/arm/mach-tegra/p852/board-p852-pinmux.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sdhci.c b/arch/arm/mach-tegra/p852/board-p852-sdhci.c index 54fd42e38ab6..f7ee9355d633 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sdhci.c +++ b/arch/arm/mach-tegra/p852/board-p852-sdhci.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sdhci.c + * arch/arm/mach-tegra/p852/board-p852-sdhci.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku1-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku1-b00.c index 1cd89c5dfd76..7ab3671d6dd7 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku1-b00.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku1-b00.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku1-b00.c + * arch/arm/mach-tegra/p852/board-p852-sku1-b00.c * * Copyright (C) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c b/arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c index 4a783fb9b635..ddacfa0528f9 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku1-c0x.c + * arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c * * Copyright (C) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku1.c b/arch/arm/mach-tegra/p852/board-p852-sku1.c index 387ba054bd84..09213c1955ae 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku1.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku1.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku1.c + * arch/arm/mach-tegra/p852/board-p852-sku1.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku13-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku13-b00.c index 39e01f660eaf..8bf74e5e98eb 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku13-b00.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku13-b00.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku13-b00.c + * arch/arm/mach-tegra/p852/board-p852-sku13-b00.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku13.c b/arch/arm/mach-tegra/p852/board-p852-sku13.c index 92d917e6e2c1..5009a43aa432 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku13.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku13.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku13.c + * arch/arm/mach-tegra/p852/board-p852-sku13.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku23-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku23-b00.c index 6f464ec3620f..70f0147faffb 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku23-b00.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku23-b00.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku23-b00.c + * arch/arm/mach-tegra/p852/board-p852-sku23-b00.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku23-c01.c b/arch/arm/mach-tegra/p852/board-p852-sku23-c01.c index f946e0ed35ee..b9ed72efc508 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku23-c01.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku23-c01.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku23-c01.c + * arch/arm/mach-tegra/p852/board-p852-sku23-c01.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku23.c b/arch/arm/mach-tegra/p852/board-p852-sku23.c index a2bc9b4ca0b6..d61a28fea12f 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku23.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku23.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku23.c + * arch/arm/mach-tegra/p852/board-p852-sku23.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku3.c b/arch/arm/mach-tegra/p852/board-p852-sku3.c index 380df9a7439a..ee6be1c53f7a 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku3.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku3.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku3.c + * arch/arm/mach-tegra/p852/board-p852-sku3.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku5-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku5-b00.c index 59f6f13f7729..506fab25c968 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku5-b00.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku5-b00.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku5_b00.c + * arch/arm/mach-tegra/p852/board-p852-sku5-b00.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku5-c01.c b/arch/arm/mach-tegra/p852/board-p852-sku5-c01.c index f9c8e72911b6..0dda7a21c94d 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku5-c01.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku5-c01.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku5-c01.c + * arch/arm/mach-tegra/p852/board-p852-sku5-c01.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku8-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku8-b00.c index 4cc4d53d980f..e9a11b427de1 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku8-b00.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku8-b00.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku8-b00.c + * arch/arm/mach-tegra/p852/board-p852-sku8-b00.c * * Copyright (C) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku8-c01.c b/arch/arm/mach-tegra/p852/board-p852-sku8-c01.c index 71210cd12b90..f1da518f2eef 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku8-c01.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku8-c01.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku8-c00.c + * arch/arm/mach-tegra/p852/board-p852-sku8-c01.c * * Copyright (C) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku9-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku9-b00.c index 7c3d9c3d9a3d..fd2f1cb95716 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku9-b00.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku9-b00.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku9-b00.c + * arch/arm/mach-tegra/p852/board-p852-sku9-b00.c * * Copyright (C) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852-sku9-c01.c b/arch/arm/mach-tegra/p852/board-p852-sku9-c01.c index 94c79294fb47..9add0e83a0d3 100644 --- a/arch/arm/mach-tegra/p852/board-p852-sku9-c01.c +++ b/arch/arm/mach-tegra/p852/board-p852-sku9-c01.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852-sku9-c00.c + * arch/arm/mach-tegra/p852/board-p852-sku9-c01.c * * Copyright (C) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852.c b/arch/arm/mach-tegra/p852/board-p852.c index 0382d7306f42..fba0db4a1a05 100644 --- a/arch/arm/mach-tegra/p852/board-p852.c +++ b/arch/arm/mach-tegra/p852/board-p852.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852.c + * arch/arm/mach-tegra/p852/board-p852.c * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/p852/board-p852.h b/arch/arm/mach-tegra/p852/board-p852.h index 8e8f1444029c..58934e6dc1cc 100644 --- a/arch/arm/mach-tegra/p852/board-p852.h +++ b/arch/arm/mach-tegra/p852/board-p852.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/board-p852.h + * arch/arm/mach-tegra/p852/board-p852.h * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c index 04d3a5db3f7e..efeb2c48277e 100644 --- a/arch/arm/mach-tegra/pcie.c +++ b/arch/arm/mach-tegra/pcie.c @@ -289,7 +289,7 @@ struct tegra_pcie_port { int index; - u8 root_bus_nr; + int root_bus_nr; void __iomem *base; bool link_up; @@ -1262,6 +1262,7 @@ static void tegra_pcie_add_port(int index, u32 offset, u32 reset_reg) tegra_pcie.num_ports++; pp->index = index; + pp->root_bus_nr = -1; memset(pp->res, 0, sizeof(pp->res)); } diff --git a/arch/arm/mach-tegra/pm-t3.c b/arch/arm/mach-tegra/pm-t3.c index 939a9b8ad404..dbc10f229551 100644 --- a/arch/arm/mach-tegra/pm-t3.c +++ b/arch/arm/mach-tegra/pm-t3.c @@ -478,9 +478,15 @@ void tegra_lp0_cpu_mode(bool enter) struct tegra_io_dpd tegra_list_io_dpd[] = { /* sd dpd bits in dpd2 register */ +#ifndef CONFIG_MACH_APALIS_T30 +/* Hack: fix MMC1 card detection */ IO_DPD_INFO("sdhci-tegra.0", 1, 1), /* SDMMC1 */ +#endif IO_DPD_INFO("sdhci-tegra.2", 1, 2), /* SDMMC3 */ +#if !defined(CONFIG_MACH_APALIS_T30) && !defined(CONFIG_MACH_COLIBRI_T30) +/* Hack: fix eMMC detection */ IO_DPD_INFO("sdhci-tegra.3", 1, 3), /* SDMMC4 */ +#endif }; /* we want to cleanup bootloader io dpd setting in kernel */ diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h index 401c0aaf061f..284c556d2a93 100644 --- a/arch/arm/mach-tegra/pm.h +++ b/arch/arm/mach-tegra/pm.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/pm.h + * arch/arm/mach-tegra/pm.h * * Copyright (C) 2010 Google, Inc. * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index 4c0d8bec276e..c6d215fc025c 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -721,6 +721,7 @@ err_power: WARN(1, "Could not Un-Powergate %d", id); return ret; } +EXPORT_SYMBOL(tegra_unpowergate_partition); /* * Must be called with clk disabled, and returns with clk enabled diff --git a/arch/arm/mach-tegra/sleep-t2.S b/arch/arm/mach-tegra/sleep-t2.S index f70360628f34..0b77fd14c7c2 100644 --- a/arch/arm/mach-tegra/sleep-t2.S +++ b/arch/arm/mach-tegra/sleep-t2.S @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/sleep-t2.S + * arch/arm/mach-tegra/sleep-t2.S * * Copyright (c) 2010-2011, NVIDIA Corporation. * Copyright (c) 2011, Google, Inc. diff --git a/arch/arm/mach-tegra/sleep-t3.S b/arch/arm/mach-tegra/sleep-t3.S index 4ee73d581a08..ae943bde1ce2 100644 --- a/arch/arm/mach-tegra/sleep-t3.S +++ b/arch/arm/mach-tegra/sleep-t3.S @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/sleep-t3.S + * arch/arm/mach-tegra/sleep-t3.S * * Copyright (c) 2010-2011, NVIDIA Corporation. * diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 08359fcc0d31..58d2dcddbfaa 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -65,8 +65,9 @@ #define PERIPH_CLK_SOURCE_NUM \ ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4) -#define PERIPH_CLK_SOURCE_MASK (3<<30) -#define PERIPH_CLK_SOURCE_SHIFT 30 +//special handling for pwm clock source, uses 3 bits 30:28 instead of 2 bits 31:30 +#define PERIPH_CLK_SOURCE_MASK ((c->reg) != 0x110 ? (3<<PERIPH_CLK_SOURCE_SHIFT) : (7<<PERIPH_CLK_SOURCE_SHIFT)) +#define PERIPH_CLK_SOURCE_SHIFT ((c->reg) != 0x110 ? 30 : 28) #define PERIPH_CLK_SOURCE_ENABLE (1<<28) #define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF #define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF @@ -2103,9 +2104,9 @@ static const struct audio_sources { { .name = "spdif_in", .value = 0 }, { .name = "i2s1", .value = 1 }, { .name = "i2s2", .value = 2 }, + { .name = "ac97", .value = 3 }, { .name = "pll_a_out0", .value = 4 }, #if 0 /* FIXME: not implemented */ - { .name = "ac97", .value = 3 }, { .name = "ext_audio_clk2", .value = 5 }, { .name = "ext_audio_clk1", .value = 6 }, { .name = "ext_vimclk", .value = 7 }, @@ -2428,6 +2429,7 @@ struct clk tegra_list_periph_clks[] = { PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 0x31E, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB), PERIPH_CLK("kbc", "tegra-kbc", NULL, 36, 0, 0x31E, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB), PERIPH_CLK("timer", "timer", NULL, 5, 0, 0x31E, 26000000, mux_clk_m, 0), + PERIPH_CLK("ac97", "tegra20-ac97", NULL, 3, 0, 0x31E, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), PERIPH_CLK("i2s1", "tegra20-i2s.0", NULL, 11, 0x100, 0x31E, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), PERIPH_CLK("i2s2", "tegra20-i2s.1", NULL, 18, 0x104, 0x31E, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB), PERIPH_CLK("fuse", "fuse-tegra", "fuse", 39, 0, 0x31E, 26000000, mux_clk_m, PERIPH_ON_APB), @@ -2755,7 +2757,7 @@ struct tegra_cpufreq_table_data *tegra_cpufreq_table_get(void) unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate) { /* Vote on memory bus frequency based on cpu frequency */ - if (cpu_rate > 1000000000) + if (cpu_rate > 1000000) return 760000000; else if (cpu_rate >= 816000) return 600000000; /* cpu 816 MHz, emc max */ diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index f1ac82ad5c15..4986fffcfed7 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c @@ -54,6 +54,7 @@ static inline u32 emc_readl(unsigned long addr) return readl(emc + addr); } +#ifndef CONFIG_MACH_COLIBRI_T20 /* read LPDDR2 memory modes */ static int tegra_emc_read_mrr(unsigned long addr) { @@ -82,6 +83,7 @@ static int tegra_emc_read_mrr(unsigned long addr) return value; } +#endif /* !CONFIG_MACH_COLIBRI_T20 */ static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { 0x2c, /* RC */ @@ -219,18 +221,25 @@ int tegra_emc_set_rate(unsigned long rate) void tegra_init_emc(const struct tegra_emc_chip *chips, int chips_size) { int i; +#ifndef CONFIG_MACH_COLIBRI_T20 int vid; int rev_id1; int rev_id2; int pid; +#endif /* !CONFIG_MACH_COLIBRI_T20 */ int chip_matched = -1; +#ifndef CONFIG_MACH_COLIBRI_T20 +//somehow this only seems to work for LPDDR2 but we have regular DDR2 vid = tegra_emc_read_mrr(5); rev_id1 = tegra_emc_read_mrr(6); rev_id2 = tegra_emc_read_mrr(7); pid = tegra_emc_read_mrr(8); +#endif /* !CONFIG_MACH_COLIBRI_T20 */ for (i = 0; i < chips_size; i++) { +#ifndef CONFIG_MACH_COLIBRI_T20 +//for now just go with the one and only chip table if (chips[i].mem_manufacturer_id >= 0) { if (chips[i].mem_manufacturer_id != vid) continue; @@ -247,6 +256,7 @@ void tegra_init_emc(const struct tegra_emc_chip *chips, int chips_size) if (chips[i].mem_pid != pid) continue; } +#endif /* !CONFIG_MACH_COLIBRI_T20 */ chip_matched = i; break; @@ -264,9 +274,11 @@ void tegra_init_emc(const struct tegra_emc_chip *chips, int chips_size) } else { pr_err("%s: Memory not recognized, memory scaling disabled\n", __func__); +#ifndef CONFIG_MACH_COLIBRI_T20 pr_info("%s: Memory vid = 0x%04x", __func__, vid); pr_info("%s: Memory rev_id1 = 0x%04x", __func__, rev_id1); pr_info("%s: Memory rev_id2 = 0x%04x", __func__, rev_id2); pr_info("%s: Memory pid = 0x%04x", __func__, pid); +#endif /* !CONFIG_MACH_COLIBRI_T20 */ } } diff --git a/arch/arm/mach-tegra/tegra2_mc.h b/arch/arm/mach-tegra/tegra2_mc.h index 211213c5f585..9ff27cbca3f1 100644 --- a/arch/arm/mach-tegra/tegra2_mc.h +++ b/arch/arm/mach-tegra/tegra2_mc.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/tegra2_mc.c + * arch/arm/mach-tegra/tegra2_mc.h * * Memory controller bandwidth profiling interface * diff --git a/arch/arm/mach-tegra/tegra2_usb_phy.c b/arch/arm/mach-tegra/tegra2_usb_phy.c index 0292ebb75083..121a84b2bcb0 100644 --- a/arch/arm/mach-tegra/tegra2_usb_phy.c +++ b/arch/arm/mach-tegra/tegra2_usb_phy.c @@ -629,6 +629,8 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy) } else if (!phy->phy_clk_on) { return IRQ_NONE; } + } else if (!phy->phy_clk_on) { + return IRQ_NONE; } return IRQ_HANDLED; diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c index 0bc60869a3d0..fafa5a22157a 100644 --- a/arch/arm/mach-tegra/tegra3_clocks.c +++ b/arch/arm/mach-tegra/tegra3_clocks.c @@ -844,12 +844,15 @@ static int tegra3_cpu_clk_set_rate(struct clk *c, unsigned long rate) if (c->dvfs) { if (!c->dvfs->dvfs_rail) return -ENOSYS; +#if !defined(CONFIG_MACH_APALIS_T30) && !defined(CONFIG_MACH_COLIBRI_T30) +/* Hack: avoid extensive warnings being logged during boot-up. */ else if ((!c->dvfs->dvfs_rail->reg) && (clk_get_rate_locked(c) < rate)) { WARN(1, "Increasing CPU rate while regulator is not" " ready may overclock CPU\n"); return -ENOSYS; } +#endif /* !CONFIG_MACH_APALIS_T30 & !CONFIG_MACH_COLIBRI_T30 */ } /* diff --git a/arch/arm/mach-tegra/tegra3_speedo.c b/arch/arm/mach-tegra/tegra3_speedo.c index b91135c5634d..76303b4f1756 100644 --- a/arch/arm/mach-tegra/tegra3_speedo.c +++ b/arch/arm/mach-tegra/tegra3_speedo.c @@ -198,7 +198,7 @@ static void rev_sku_to_speedo_ids(int rev, int sku) break; case 0x81: /* T30 */ - case 0xb1: + case 0xb1: /* T30MQS-Ax */ switch (package_id) { case 1: /* MID => T30 */ cpu_speedo_id = 2; diff --git a/arch/arm/mach-tegra/tegra_fiq_debugger.c b/arch/arm/mach-tegra/tegra_fiq_debugger.c index 2a19a214acb5..d164d6b1d949 100644 --- a/arch/arm/mach-tegra/tegra_fiq_debugger.c +++ b/arch/arm/mach-tegra/tegra_fiq_debugger.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/fiq_debugger.c + * arch/arm/mach-tegra/tegra_fiq_debugger.c * * Serial Debugger Interface for Tegra * diff --git a/arch/arm/mach-tegra/tegra_usb_phy.h b/arch/arm/mach-tegra/tegra_usb_phy.h index 05aa88296619..ff3b979fe814 100644 --- a/arch/arm/mach-tegra/tegra_usb_phy.h +++ b/arch/arm/mach-tegra/tegra_usb_phy.h @@ -1,5 +1,5 @@ /* - * arch/arm/mach-tegra/include/mach/tegra_usb_phy.h + * arch/arm/mach-tegra/tegra_usb_phy.h * * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 2a7364c12753..b5d3dc575e0c 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -79,6 +79,7 @@ static void print_usb_plat_data_info(struct tegra_usb_phy *phy) ? "enabled" : "disabled"); } else { pr_info("vbus_gpio: %d\n", pdata->u_data.host.vbus_gpio); + pr_info("vbus_gpio_inverted: %d\n", pdata->u_data.host.vbus_gpio_inverted); pr_info("vbus_reg: %s\n", pdata->u_data.host.vbus_reg ? pdata->u_data.host.vbus_reg : "NULL"); pr_info("hot_plug: %s\n", pdata->u_data.host.hot_plug ? @@ -99,7 +100,7 @@ static void usb_host_vbus_enable(struct tegra_usb_phy *phy, bool enable) int gpio = phy->pdata->u_data.host.vbus_gpio; if (gpio == -1) return; - gpio_set_value_cansleep(gpio, enable ? 1 : 0); + gpio_set_value_cansleep(gpio, (enable != phy->pdata->u_data.host.vbus_gpio_inverted)? 1 : 0); } } @@ -326,7 +327,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev) req failed\n", phy->inst); goto fail_init; } - if (gpio_direction_output(gpio, 1) < 0) { + if (gpio_direction_output(gpio, !phy->pdata->u_data.host.vbus_gpio_inverted) < 0) { ERR("inst:[%d] host vbus gpio \ dir failed\n", phy->inst); goto fail_init; @@ -369,7 +370,7 @@ fail_init: else { int gpio = phy->pdata->u_data.host.vbus_gpio; if (gpio != -1) { - gpio_set_value_cansleep(gpio, 0); + gpio_set_value_cansleep(gpio, phy->pdata->u_data.host.vbus_gpio_inverted); gpio_free(gpio); } } @@ -386,6 +387,7 @@ fail_nomem: fail_inval: return ERR_PTR(err); } +EXPORT_SYMBOL_GPL(tegra_usb_phy_open); void tegra_usb_phy_close(struct tegra_usb_phy *phy) { @@ -410,7 +412,7 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy) else { int gpio = phy->pdata->u_data.host.vbus_gpio; if (gpio != -1) { - gpio_set_value_cansleep(gpio, 0); + gpio_set_value_cansleep(gpio, phy->pdata->u_data.host.vbus_gpio_inverted); gpio_free(gpio); } } @@ -427,6 +429,7 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy) devm_kfree(&phy->pdev->dev, phy->pdata); devm_kfree(&phy->pdev->dev, phy); } +EXPORT_SYMBOL_GPL(tegra_usb_phy_close); irqreturn_t tegra_usb_phy_irq(struct tegra_usb_phy *phy) { @@ -452,6 +455,7 @@ int tegra_usb_phy_init(struct tegra_usb_phy *phy) return status; } +EXPORT_SYMBOL_GPL(tegra_usb_phy_init); int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) { @@ -502,6 +506,7 @@ int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) return err; } +EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off); int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) { @@ -546,6 +551,7 @@ int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) return status; } +EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on); int tegra_usb_phy_reset(struct tegra_usb_phy *phy) { @@ -685,6 +691,7 @@ bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy) return status; } +EXPORT_SYMBOL_GPL(tegra_usb_phy_charger_detected); bool tegra_usb_phy_hw_accessible(struct tegra_usb_phy *phy) { @@ -704,11 +711,13 @@ bool tegra_usb_phy_has_hostpc(struct tegra_usb_phy *phy) { return phy->pdata->has_hostpc; } +EXPORT_SYMBOL_GPL(tegra_usb_phy_has_hostpc); bool tegra_usb_phy_otg_supported(struct tegra_usb_phy *phy) { return phy->pdata->port_otg; } +EXPORT_SYMBOL_GPL(tegra_usb_phy_otg_supported); void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy) { @@ -724,6 +733,7 @@ void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy) writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG2); } } +EXPORT_SYMBOL_GPL(tegra_usb_phy_memory_prefetch_on); void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy) { @@ -739,3 +749,4 @@ void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy) writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG2); } } +EXPORT_SYMBOL_GPL(tegra_usb_phy_memory_prefetch_off); diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 3b5ea68acbb8..aa33949fef60 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -20,6 +20,7 @@ #include <linux/highmem.h> #include <linux/perf_event.h> +#include <asm/exception.h> #include <asm/system.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c index c11064517f56..f5519a93147d 100644 --- a/arch/arm/mm/pageattr.c +++ b/arch/arm/mm/pageattr.c @@ -35,7 +35,9 @@ extern void __flush_dcache_page(struct address_space *, struct page *); static void inner_flush_cache_all(void) { +#ifdef CONFIG_CPU_CACHE_V7 on_each_cpu(v7_flush_kern_cache_all, NULL, 1); +#endif } #if defined(CONFIG_CPA) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 978683edfead..3f55d34e3f39 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -946,7 +946,7 @@ shenzhou MACH_SHENZHOU SHENZHOU 3319 cwme9210 MACH_CWME9210 CWME9210 3320 cwme9210js MACH_CWME9210JS CWME9210JS 3321 pgs_v1 MACH_PGS_SITARA PGS_SITARA 3322 -colibri_tegra2 MACH_COLIBRI_TEGRA2 COLIBRI_TEGRA2 3323 +colibri_t20 MACH_COLIBRI_T20 COLIBRI_T20 3323 w21 MACH_W21 W21 3324 polysat1 MACH_POLYSAT1 POLYSAT1 3325 dataway MACH_DATAWAY DATAWAY 3326 @@ -1119,3 +1119,5 @@ kai MACH_KAI KAI 3897 p852 MACH_P852 P852 3667 e1853 MACH_E1853 E1853 4241 tai MACH_TAI TAI 4311 +colibri_t30 MACH_COLIBRI_T30 COLIBRI_T30 4493 +apalis_t30 MACH_APALIS_T30 APALIS_T30 4513 diff --git a/drivers/ata/ahci-tegra.c b/drivers/ata/ahci-tegra.c index c90472827b9b..32bf46940b0f 100644 --- a/drivers/ata/ahci-tegra.c +++ b/drivers/ata/ahci-tegra.c @@ -217,6 +217,7 @@ enum sata_state { }; char *sata_power_rails[] = { + "avdd_plle", "avdd_sata", "vdd_sata", "hvdd_sata", diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index dce9e68241e6..1b60fe6de776 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -34,6 +34,8 @@ #include <linux/mutex.h> #include <linux/sysfs.h> +#include <linux/lm95245.h> + #define DEVNAME "lm95245" static const unsigned short normal_i2c[] = { @@ -93,6 +95,7 @@ static const unsigned short normal_i2c[] = { #define RATE_CR1000 0x02 #define RATE_CR2500 0x03 +#define STATUS1_ROS 0x10 #define STATUS1_DIODE_FAULT 0x04 #define STATUS1_RTCRIT 0x02 #define STATUS1_LOC 0x01 @@ -107,12 +110,32 @@ static const u8 lm95245_reg_address[] = { LM95245_REG_R_REMOTE_TEMPL_S, LM95245_REG_R_REMOTE_TEMPH_U, LM95245_REG_R_REMOTE_TEMPL_U, + LM95245_REG_RW_REMOTE_OS_LIMIT, LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT, LM95245_REG_RW_REMOTE_TCRIT_LIMIT, LM95245_REG_RW_COMMON_HYSTERESIS, LM95245_REG_R_STATUS1, }; +/* Indices and offsets into above register array */ + +enum { + INDEX_LOCAL_TEMP = 0, + INDEX_REMOTE_TEMP = 2, + INDEX_REMOTE_OS_LIMIT = 6, + INDEX_LOCAL_OS_TCRIT_LIMIT, + INDEX_REMOTE_TCRIT_LIMIT, + INDEX_COMMON_HYSTERESIS, + INDEX_STATUS1, +}; + +enum { + OFFSET_HIGH_SIGNED = 0, + OFFSET_LOW_SIGNED, + OFFSET_HIGH_UNSIGNED, + OFFSET_LOW_UNSIGNED, +}; + /* Client data (each client gets its own) */ struct lm95245_data { struct device *hwmon_dev; @@ -214,24 +237,42 @@ static unsigned long lm95245_set_conversion_rate(struct i2c_client *client, } /* Sysfs stuff */ -static ssize_t show_input(struct device *dev, struct device_attribute *attr, - char *buf) +void thermal_get_temp(struct device *dev, int *temp, int index) { struct lm95245_data *data = lm95245_update_device(dev); - int temp; - int index = to_sensor_dev_attr(attr)->index; /* - * Index 0 (Local temp) is always signed - * Index 2 (Remote temp) has both signed and unsigned data + * Local temp is always signed + * Remote temp has both signed and unsigned data * use signed calculation for remote if signed bit is set */ - if (index == 0 || data->regs[index] & 0x80) - temp = temp_from_reg_signed(data->regs[index], - data->regs[index + 1]); + if (index == INDEX_LOCAL_TEMP || data->regs[index + OFFSET_HIGH_SIGNED] & 0x80) + *temp = temp_from_reg_signed(data->regs[index + OFFSET_HIGH_SIGNED], + data->regs[index + OFFSET_LOW_SIGNED]); else - temp = temp_from_reg_unsigned(data->regs[index + 2], - data->regs[index + 3]); + *temp = temp_from_reg_unsigned(data->regs[index + OFFSET_HIGH_UNSIGNED], + data->regs[index + OFFSET_LOW_UNSIGNED]); +} + +void lm95245_get_local_temp(struct device *dev, int *temp) +{ + thermal_get_temp(dev, temp, INDEX_LOCAL_TEMP); +} +EXPORT_SYMBOL(lm95245_get_local_temp); + +void lm95245_get_remote_temp(struct device *dev, int *temp) +{ + thermal_get_temp(dev, temp, INDEX_REMOTE_TEMP); +} +EXPORT_SYMBOL(lm95245_get_remote_temp); + +static ssize_t show_input(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int temp = 0; + int index = to_sensor_dev_attr(attr)->index; + + thermal_get_temp(dev, &temp, index); return snprintf(buf, PAGE_SIZE - 1, "%d\n", temp); } @@ -246,20 +287,14 @@ static ssize_t show_limit(struct device *dev, struct device_attribute *attr, data->regs[index] * 1000); } -static ssize_t set_limit(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +void thermal_set_limit(struct device *dev, int val, int index) { struct i2c_client *client = to_i2c_client(dev); struct lm95245_data *data = i2c_get_clientdata(client); - int index = to_sensor_dev_attr(attr)->index; - unsigned long val; - - if (strict_strtoul(buf, 10, &val) < 0) - return -EINVAL; val /= 1000; - val = SENSORS_LIMIT(val, 0, (index == 6 ? 127 : 255)); + val = SENSORS_LIMIT(val, 0, (index == INDEX_LOCAL_OS_TCRIT_LIMIT ? 127 : 255)); mutex_lock(&data->update_lock); @@ -268,6 +303,36 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr, i2c_smbus_write_byte_data(client, lm95245_reg_address[index], val); mutex_unlock(&data->update_lock); +} + +void lm95245_set_remote_os_limit(struct device *dev, int val) +{ + thermal_set_limit(dev, val, INDEX_REMOTE_OS_LIMIT); +} +EXPORT_SYMBOL(lm95245_set_remote_os_limit); + +void lm95245_set_remote_critical_limit(struct device *dev, int val) +{ + thermal_set_limit(dev, val, INDEX_REMOTE_TCRIT_LIMIT); +} +EXPORT_SYMBOL(lm95245_set_remote_critical_limit); + +void lm95245_set_local_shared_os__critical_limit(struct device *dev, int val) +{ + thermal_set_limit(dev, val, INDEX_LOCAL_OS_TCRIT_LIMIT); +} +EXPORT_SYMBOL(lm95245_set_local_shared_os__critical_limit); + +static ssize_t set_limit(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + unsigned long val; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + thermal_set_limit(dev, (int)val, index); return count; } @@ -345,7 +410,7 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, int index = to_sensor_dev_attr(attr)->index; return snprintf(buf, PAGE_SIZE - 1, "%d\n", - !!(data->regs[9] & index)); + !!(data->regs[INDEX_STATUS1] & index)); } static ssize_t show_interval(struct device *dev, struct device_attribute *attr, @@ -375,19 +440,23 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr, return count; } -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, INDEX_LOCAL_TEMP); static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit, - set_limit, 6); + set_limit, INDEX_LOCAL_OS_TCRIT_LIMIT); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit, - set_crit_hyst, 8); + set_crit_hyst, INDEX_COMMON_HYSTERESIS); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, STATUS1_LOC); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, INDEX_REMOTE_TEMP); +static SENSOR_DEVICE_ATTR(temp2_os, S_IWUSR | S_IRUGO, show_limit, + set_limit, INDEX_REMOTE_OS_LIMIT); static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit, - set_limit, 7); + set_limit, INDEX_REMOTE_TCRIT_LIMIT); static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit, - set_crit_hyst, 8); + set_crit_hyst, INDEX_COMMON_HYSTERESIS); +static SENSOR_DEVICE_ATTR(temp2_os_alarm, S_IRUGO, show_alarm, NULL, + STATUS1_ROS); static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, STATUS1_RTCRIT); static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, @@ -404,8 +473,10 @@ static struct attribute *lm95245_attributes[] = { &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_os.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_os_alarm.dev_attr.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp2_type.dev_attr.attr, &sensor_dev_attr_temp2_fault.dev_attr.attr, @@ -454,6 +525,13 @@ static void lm95245_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG1, data->config1); } + + /* Configure over-temperature shutdown (OS) output pin */ + if (client->dev.platform_data && ((struct lm95245_platform_data*)(client->dev.platform_data))->enable_os_pin) { + data->config2 |= CFG2_OS_A0; + i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG2, + data->config2); + } } static int lm95245_probe(struct i2c_client *new_client, @@ -485,6 +563,10 @@ static int lm95245_probe(struct i2c_client *new_client, goto exit_remove_files; } + /* Notify callback that probe is done */ + if (new_client->dev.platform_data && ((struct lm95245_platform_data*)(new_client->dev.platform_data))->probe_callback) + ((struct lm95245_platform_data*)(new_client->dev.platform_data))->probe_callback(&new_client->dev); + return 0; exit_remove_files: diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 1def6f105d6b..ec1bd9009288 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -790,7 +790,7 @@ static int gpio_keys_suspend(struct device *dev) for (i = 0; i < ddata->n_buttons; i++) { struct gpio_button_data *bdata = &ddata->data[i]; if (bdata->button->wakeup) - enable_irq_wake(bdata->irq); + WARN_ON(enable_irq_wake(bdata->irq)); } } diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a8fc74f730dd..936f1e71a21f 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -770,4 +770,11 @@ config TOUCHSCREEN_SYN_RMI4_SPI To compile this driver as a module, choose M here: the module will be called rmi-spi. +config TOUCHSCREEN_FUSION_F0710A + tristate "TouchRevolution Fusion F0710A Touchscreens" + depends on I2C + help + Say Y here if you want to support the multi-touch input driver for + the TouchRevolution Fusion 7 and 10 panels. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 9c42d2100b5c..2fa571b65088 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -64,3 +64,4 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_RM31080A) += rm31080a_ts.o obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi4/ +obj-$(CONFIG_TOUCHSCREEN_FUSION_F0710A) += fusion_F0710A.o diff --git a/drivers/input/touchscreen/fusion_F0710A.c b/drivers/input/touchscreen/fusion_F0710A.c new file mode 100644 index 000000000000..c5c0f1fc38ea --- /dev/null +++ b/drivers/input/touchscreen/fusion_F0710A.c @@ -0,0 +1,524 @@ +/* + * "fusion_F0710A" touchscreen driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/workqueue.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <asm/irq.h> +#include <linux/gpio.h> +#include <linux/input/fusion_F0710A.h> + +#include "fusion_F0710A.h" + +#define DRV_NAME "fusion_F0710A" + + +static struct fusion_F0710A_data fusion_F0710A; + +static unsigned short normal_i2c[] = { fusion_F0710A_I2C_SLAVE_ADDR, I2C_CLIENT_END }; + +//I2C_CLIENT_INSMOD; + +static int fusion_F0710A_write_u8(u8 addr, u8 data) +{ + return i2c_smbus_write_byte_data(fusion_F0710A.client, addr, data); +} + +static int fusion_F0710A_read_u8(u8 addr) +{ + return i2c_smbus_read_byte_data(fusion_F0710A.client, addr); +} + +static int fusion_F0710A_read_block(u8 addr, u8 len, u8 *data) +{ +#if 0 + /* When i2c_smbus_read_i2c_block_data() takes a block length parameter, we can do + * this. lm-sensors lists hints this has been fixed, but I can't tell whether it + * was or will be merged upstream. */ + + return i2c_smbus_read_i2c_block_data(&fusion_F0710A.client, addr, data); +#else + u8 msgbuf0[1] = { addr }; + u16 slave = fusion_F0710A.client->addr; + u16 flags = fusion_F0710A.client->flags; + struct i2c_msg msg[2] = { { slave, flags, 1, msgbuf0 }, + { slave, flags | I2C_M_RD, len, data } + }; + + return i2c_transfer(fusion_F0710A.client->adapter, msg, ARRAY_SIZE(msg)); +#endif +} + + +static int fusion_F0710A_register_input(void) +{ + int ret; + struct input_dev *dev; + + dev = fusion_F0710A.input = input_allocate_device(); + if (dev == NULL) + return -ENOMEM; + + dev->name = "fusion_F0710A"; + + set_bit(EV_KEY, dev->evbit); + set_bit(EV_ABS, dev->evbit); + + input_set_abs_params(dev, ABS_MT_POSITION_X, 0, fusion_F0710A.info.xres-1, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, fusion_F0710A.info.yres-1, 0, 0); +#ifdef CONFIG_ANDROID + input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0); +#else + input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(dev, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0); +#endif + + input_set_abs_params(dev, ABS_X, 0, fusion_F0710A.info.xres-1, 0, 0); + input_set_abs_params(dev, ABS_Y, 0, fusion_F0710A.info.yres-1, 0, 0); + input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); + + ret = input_register_device(dev); + if (ret < 0) + goto bail1; + + return 0; + +bail1: + input_free_device(dev); + return ret; +} + +#define WC_RETRY_COUNT 3 +static int fusion_F0710A_write_complete(void) +{ + int ret, i; + + for(i=0; i<WC_RETRY_COUNT; i++) + { + ret = fusion_F0710A_write_u8(fusion_F0710A_SCAN_COMPLETE, 0); + if(ret == 0) + break; + else + dev_err(&fusion_F0710A.client->dev, "Write complete failed(%d): %d\n", i, ret); + } + + return ret; +} + +#define DATA_START fusion_F0710A_DATA_INFO +#define DATA_END fusion_F0710A_SEC_TIDTS +#define DATA_LEN (DATA_END - DATA_START + 1) +#define DATA_OFF(x) ((x) - DATA_START) + +static int fusion_F0710A_read_sensor(void) +{ + int ret; + u8 data[DATA_LEN]; + +#define DATA(x) (data[DATA_OFF(x)]) + /* To ensure data coherency, read the sensor with a single transaction. */ + ret = fusion_F0710A_read_block(DATA_START, DATA_LEN, data); + if (ret < 0) { + dev_err(&fusion_F0710A.client->dev, + "Read block failed: %d\n", ret); + + return ret; + } + + fusion_F0710A.f_num = DATA(fusion_F0710A_DATA_INFO)&0x03; + + fusion_F0710A.y1 = DATA(fusion_F0710A_POS_X1_HI) << 8; + fusion_F0710A.y1 |= DATA(fusion_F0710A_POS_X1_LO); + fusion_F0710A.x1 = DATA(fusion_F0710A_POS_Y1_HI) << 8; + fusion_F0710A.x1 |= DATA(fusion_F0710A_POS_Y1_LO); + fusion_F0710A.z1 = DATA(fusion_F0710A_FIR_PRESS); + fusion_F0710A.tip1 = DATA(fusion_F0710A_FIR_TIDTS)&0x0f; + fusion_F0710A.tid1 = (DATA(fusion_F0710A_FIR_TIDTS)&0xf0)>>4; + + + fusion_F0710A.y2 = DATA(fusion_F0710A_POS_X2_HI) << 8; + fusion_F0710A.y2 |= DATA(fusion_F0710A_POS_X2_LO); + fusion_F0710A.x2 = DATA(fusion_F0710A_POS_Y2_HI) << 8; + fusion_F0710A.x2 |= DATA(fusion_F0710A_POS_Y2_LO); + fusion_F0710A.z2 = DATA(fusion_F0710A_SEC_PRESS); + fusion_F0710A.tip2 = DATA(fusion_F0710A_SEC_TIDTS)&0x0f; + fusion_F0710A.tid2 =(DATA(fusion_F0710A_SEC_TIDTS)&0xf0)>>4; +#undef DATA + + return 0; +} + +#define val_cut_max(x, max, reverse) \ +do \ +{ \ + if(x > max) \ + x = max; \ + if(reverse) \ + x = (max) - (x); \ +} \ +while(0) + +static void fusion_F0710A_wq(struct work_struct *work) +{ + struct input_dev *dev = fusion_F0710A.input; + int save_points = 0; + int x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0; + + if (fusion_F0710A_read_sensor() < 0) + goto restore_irq; + +#ifdef DEBUG + printk(KERN_DEBUG "tip1, tid1, x1, y1, z1 (%x,%x,%d,%d,%d); tip2, tid2, x2, y2, z2 (%x,%x,%d,%d,%d)\n", + fusion_F0710A.tip1, fusion_F0710A.tid1, fusion_F0710A.x1, fusion_F0710A.y1, fusion_F0710A.z1, + fusion_F0710A.tip2, fusion_F0710A.tid2, fusion_F0710A.x2, fusion_F0710A.y2, fusion_F0710A.z2); +#endif /* DEBUG */ + + val_cut_max(fusion_F0710A.x1, fusion_F0710A.info.xres-1, fusion_F0710A.info.xy_reverse); + val_cut_max(fusion_F0710A.y1, fusion_F0710A.info.yres-1, fusion_F0710A.info.xy_reverse); + val_cut_max(fusion_F0710A.x2, fusion_F0710A.info.xres-1, fusion_F0710A.info.xy_reverse); + val_cut_max(fusion_F0710A.y2, fusion_F0710A.info.yres-1, fusion_F0710A.info.xy_reverse); + + if(fusion_F0710A.tip1 == 1) + { + if(fusion_F0710A.tid1 == 1) + { + /* first point */ + x1 = fusion_F0710A.x1; + y1 = fusion_F0710A.y1; + z1 = fusion_F0710A.z1; + save_points |= fusion_F0710A_SAVE_PT1; + } + else if(fusion_F0710A.tid1 == 2) + { + /* second point ABS_DISTANCE second point pressure, BTN_2 second point touch */ + x2 = fusion_F0710A.x1; + y2 = fusion_F0710A.y1; + z2 = fusion_F0710A.z1; + save_points |= fusion_F0710A_SAVE_PT2; + } + } + + if(fusion_F0710A.tip2 == 1) + { + if(fusion_F0710A.tid2 == 2) + { + /* second point ABS_DISTANCE second point pressure, BTN_2 second point touch */ + x2 = fusion_F0710A.x2; + y2 = fusion_F0710A.y2; + z2 = fusion_F0710A.z2; + save_points |= fusion_F0710A_SAVE_PT2; + } + else if(fusion_F0710A.tid2 == 1)/* maybe this will never happen */ + { + /* first point */ + x1 = fusion_F0710A.x2; + y1 = fusion_F0710A.y2; + z1 = fusion_F0710A.z2; + save_points |= fusion_F0710A_SAVE_PT1; + } + } + +#ifdef CONFIG_ANDROID + if(z1) + { + input_report_abs(dev, ABS_MT_TRACKING_ID, 1); + input_report_abs(dev, ABS_MT_POSITION_X, x1); + input_report_abs(dev, ABS_MT_POSITION_Y, y1); + } + input_mt_sync(dev); + + if(z2) + { + input_report_abs(dev, ABS_MT_TRACKING_ID, 2); + input_report_abs(dev, ABS_MT_POSITION_X, x2); + input_report_abs(dev, ABS_MT_POSITION_Y, y2); + } + input_mt_sync(dev); +#else /* CONFIG_ANDROID */ + input_report_abs(dev, ABS_MT_TOUCH_MAJOR, z1); + input_report_abs(dev, ABS_MT_WIDTH_MAJOR, 1); + input_report_abs(dev, ABS_MT_POSITION_X, x1); + input_report_abs(dev, ABS_MT_POSITION_Y, y1); + input_mt_sync(dev); + input_report_abs(dev, ABS_MT_TOUCH_MAJOR, z2); + input_report_abs(dev, ABS_MT_WIDTH_MAJOR, 2); + input_report_abs(dev, ABS_MT_POSITION_X, x2); + input_report_abs(dev, ABS_MT_POSITION_Y, y2); + input_mt_sync(dev); +#endif /* CONFIG_ANDROID */ + + input_report_abs(dev, ABS_X, x1); + input_report_abs(dev, ABS_Y, y1); + input_report_abs(dev, ABS_PRESSURE, z1); + input_report_key(dev, BTN_TOUCH, fusion_F0710A.tip1); + + input_sync(dev); + +restore_irq: + enable_irq(fusion_F0710A.client->irq); + + /* Clear fusion_F0710A interrupt */ + fusion_F0710A_write_complete(); +} +static DECLARE_WORK(fusion_F0710A_work, fusion_F0710A_wq); + +static irqreturn_t fusion_F0710A_interrupt(int irq, void *dev_id) +{ + disable_irq_nosync(fusion_F0710A.client->irq); + + queue_work(fusion_F0710A.workq, &fusion_F0710A_work); + + return IRQ_HANDLED; +} + +const static u8* g_ver_product[4] = { + "10Z8", "70Z7", "43Z6", "" +}; + +static int fusion_F0710A_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct fusion_f0710a_init_data *pdata = i2c->dev.platform_data; + int ret; + u8 ver_product, ver_id; + u32 version; + + if (pdata == NULL) + { + dev_err(&i2c->dev, "No platform data for Fusion driver\n"); + return -ENODEV; + } + + /* Request pinmuxing, if necessary */ + if (pdata->pinmux_fusion_pins != NULL) + { + ret = pdata->pinmux_fusion_pins(); + if (ret < 0) { + dev_err(&i2c->dev, "muxing GPIOs failed\n"); + return -ENODEV; + } + } + + if ((gpio_request(pdata->gpio_int, "Fusion pen down interrupt") == 0) && + (gpio_direction_input(pdata->gpio_int) == 0)) { + gpio_export(pdata->gpio_int, 0); + } else { + dev_warn(&i2c->dev, "Could not obtain GPIO for Fusion pen down\n"); + return -ENODEV; + } + + if ((gpio_request(pdata->gpio_reset, "Fusion reset") == 0) && + (gpio_direction_output(pdata->gpio_reset, 1) == 0)) { + + /* Generate a 0 => 1 edge explicitly, and wait for startup... */ + gpio_set_value(pdata->gpio_reset, 0); + msleep(10); + gpio_set_value(pdata->gpio_reset, 1); + /* Wait for startup (up to 125ms according to datasheet) */ + msleep(125); + + gpio_export(pdata->gpio_reset, 0); + } else { + dev_warn(&i2c->dev, "Could not obtain GPIO for Fusion reset\n"); + ret = -ENODEV; + goto bail0; + } + + /* Use Pen Down GPIO as sampling interrupt */ + i2c->irq = gpio_to_irq(pdata->gpio_int); + + if(!i2c->irq) + { + dev_err(&i2c->dev, "fusion_F0710A irq < 0 \n"); + ret = -ENOMEM; + goto bail1; + } + + /* Attach the I2C client */ + fusion_F0710A.client = i2c; + i2c_set_clientdata(i2c, &fusion_F0710A); + + dev_info(&i2c->dev, "Touchscreen registered with bus id (%d) with slave address 0x%x\n", + i2c_adapter_id(fusion_F0710A.client->adapter), fusion_F0710A.client->addr); + + /* Read out a lot of registers */ + ret = fusion_F0710A_read_u8(fusion_F0710A_VIESION_INFO_LO); + if (ret < 0) { + dev_err(&i2c->dev, "query failed: %d\n", ret); + goto bail1; + } + ver_product = (((u8)ret) & 0xc0) >> 6; + version = (10 + ((((u32)ret)&0x30) >> 4)) * 100000; + version += (((u32)ret)&0xf) * 1000; + /* Read out a lot of registers */ + ret = fusion_F0710A_read_u8(fusion_F0710A_VIESION_INFO); + if (ret < 0) { + dev_err(&i2c->dev, "query failed: %d\n", ret); + goto bail1; + } + ver_id = ((u8)(ret) & 0x6) >> 1; + version += ((((u32)ret) & 0xf8) >> 3) * 10; + version += (((u32)ret) & 0x1) + 1; /* 0 is build 1, 1 is build 2 */ + dev_info(&i2c->dev, "version product %s(%d)\n", g_ver_product[ver_product] ,ver_product); + dev_info(&i2c->dev, "version id %s(%d)\n", ver_id ? "1.4" : "1.0", ver_id); + dev_info(&i2c->dev, "version series (%d)\n", version); + + switch(ver_product) + { + case fusion_F0710A_VIESION_07: /* 7 inch */ + fusion_F0710A.info.xres = fusion_F0710A07_XMAX; + fusion_F0710A.info.yres = fusion_F0710A07_YMAX; + fusion_F0710A.info.xy_reverse = fusion_F0710A07_REV; + break; + case fusion_F0710A_VIESION_43: /* 4.3 inch */ + fusion_F0710A.info.xres = fusion_F0710A43_XMAX; + fusion_F0710A.info.yres = fusion_F0710A43_YMAX; + fusion_F0710A.info.xy_reverse = fusion_F0710A43_REV; + break; + default: /* fusion_F0710A_VIESION_10 10 inch */ + fusion_F0710A.info.xres = fusion_F0710A10_XMAX; + fusion_F0710A.info.yres = fusion_F0710A10_YMAX; + fusion_F0710A.info.xy_reverse = fusion_F0710A10_REV; + break; + } + + /* Register the input device. */ + ret = fusion_F0710A_register_input(); + if (ret < 0) { + dev_err(&i2c->dev, "can't register input: %d\n", ret); + goto bail1; + } + + /* Create a worker thread */ + fusion_F0710A.workq = create_singlethread_workqueue(DRV_NAME); + if (fusion_F0710A.workq == NULL) { + dev_err(&i2c->dev, "can't create work queue\n"); + ret = -ENOMEM; + goto bail2; + } + + + /* Register for the interrupt and enable it. Our handler will + * start getting invoked after this call. */ + ret = request_irq(i2c->irq, fusion_F0710A_interrupt, IRQF_TRIGGER_RISING, + i2c->name, &fusion_F0710A); + if (ret < 0) { + dev_err(&i2c->dev, "can't get irq %d: %d\n", i2c->irq, ret); + goto bail3; + } + /* clear the irq first */ + ret = fusion_F0710A_write_u8(fusion_F0710A_SCAN_COMPLETE, 0); + if (ret < 0) { + dev_err(&i2c->dev, "Clear irq failed: %d\n", ret); + goto bail4; + } + + return 0; + +bail4: + free_irq(i2c->irq, &fusion_F0710A); + +bail3: + destroy_workqueue(fusion_F0710A.workq); + fusion_F0710A.workq = NULL; + +bail2: + input_unregister_device(fusion_F0710A.input); +bail1: + gpio_free(pdata->gpio_reset); +bail0: + gpio_free(pdata->gpio_int); + + return ret; +} + +#ifdef CONFIG_PM_SLEEP +static int fusion_F0710A_suspend(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + disable_irq(i2c->irq); + flush_workqueue(fusion_F0710A.workq); + + return 0; +} + +static int fusion_F0710A_resume(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + enable_irq(i2c->irq); + + return 0; +} +#endif + +static int fusion_F0710A_remove(struct i2c_client *i2c) +{ + struct fusion_f0710a_init_data *pdata = i2c->dev.platform_data; + + gpio_free(pdata->gpio_int); + gpio_free(pdata->gpio_reset); + destroy_workqueue(fusion_F0710A.workq); + free_irq(i2c->irq, &fusion_F0710A); + input_unregister_device(fusion_F0710A.input); + i2c_set_clientdata(i2c, NULL); + + dev_info(&i2c->dev, "driver removed\n"); + + return 0; +} + +static struct i2c_device_id fusion_F0710A_id[] = { + {"fusion_F0710A", 0}, + {}, +}; + +static const struct dev_pm_ops fusion_F0710A_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fusion_F0710A_suspend, fusion_F0710A_resume) +}; + +static struct i2c_driver fusion_F0710A_i2c_drv = { + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .pm = &fusion_F0710A_pm_ops, + }, + .probe = fusion_F0710A_probe, + .remove = fusion_F0710A_remove, + .id_table = fusion_F0710A_id, + .address_list = normal_i2c, +}; + +static int __init fusion_F0710A_init( void ) +{ + int ret; + + memset(&fusion_F0710A, 0, sizeof(fusion_F0710A)); + + /* Probe for fusion_F0710A on I2C. */ + ret = i2c_add_driver(&fusion_F0710A_i2c_drv); + if (ret < 0) { + printk(KERN_WARNING DRV_NAME " can't add i2c driver: %d\n", ret); + } + + return ret; +} + +static void __exit fusion_F0710A_exit( void ) +{ + i2c_del_driver(&fusion_F0710A_i2c_drv); +} +module_init(fusion_F0710A_init); +module_exit(fusion_F0710A_exit); + +MODULE_DESCRIPTION("fusion_F0710A Touchscreen Driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/touchscreen/fusion_F0710A.h b/drivers/input/touchscreen/fusion_F0710A.h new file mode 100644 index 000000000000..85f8210345a9 --- /dev/null +++ b/drivers/input/touchscreen/fusion_F0710A.h @@ -0,0 +1,87 @@ +/* + * "fusion_F0710A" touchscreen driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* I2C slave address */ +#define fusion_F0710A_I2C_SLAVE_ADDR 0x10 + +/* I2C registers */ +#define fusion_F0710A_DATA_INFO 0x00 + +/* First Point*/ +#define fusion_F0710A_POS_X1_HI 0x01 /* 16-bit register, MSB */ +#define fusion_F0710A_POS_X1_LO 0x02 /* 16-bit register, LSB */ +#define fusion_F0710A_POS_Y1_HI 0x03 /* 16-bit register, MSB */ +#define fusion_F0710A_POS_Y1_LO 0x04 /* 16-bit register, LSB */ +#define fusion_F0710A_FIR_PRESS 0X05 +#define fusion_F0710A_FIR_TIDTS 0X06 + +/* Second Point */ +#define fusion_F0710A_POS_X2_HI 0x07 /* 16-bit register, MSB */ +#define fusion_F0710A_POS_X2_LO 0x08 /* 16-bit register, LSB */ +#define fusion_F0710A_POS_Y2_HI 0x09 /* 16-bit register, MSB */ +#define fusion_F0710A_POS_Y2_LO 0x0A /* 16-bit register, LSB */ +#define fusion_F0710A_SEC_PRESS 0x0B +#define fusion_F0710A_SEC_TIDTS 0x0C + +#define fusion_F0710A_VIESION_INFO_LO 0X0E +#define fusion_F0710A_VIESION_INFO 0X0F + +#define fusion_F0710A_RESET 0x10 +#define fusion_F0710A_SCAN_COMPLETE 0x11 + + +#define fusion_F0710A_VIESION_10 0 +#define fusion_F0710A_VIESION_07 1 +#define fusion_F0710A_VIESION_43 2 + +/* fusion_F0710A 10 inch panel */ +#define fusion_F0710A10_XMAX 2275 +#define fusion_F0710A10_YMAX 1275 +#define fusion_F0710A10_REV 1 + +/* fusion_F0710A 7 inch panel */ +#define fusion_F0710A07_XMAX 1500 +#define fusion_F0710A07_YMAX 900 +#define fusion_F0710A07_REV 0 + +/* fusion_F0710A 4.3 inch panel */ +#define fusion_F0710A43_XMAX 900 +#define fusion_F0710A43_YMAX 500 +#define fusion_F0710A43_REV 0 + +#define fusion_F0710A_SAVE_PT1 0x1 +#define fusion_F0710A_SAVE_PT2 0x2 + + + +/* fusion_F0710A touch screen information */ +struct fusion_F0710A_info { + int xres; /* x resolution */ + int yres; /* y resolution */ + int xy_reverse; /* if need reverse in the x,y value x=xres-1-x, y=yres-1-y*/ +}; + +struct fusion_F0710A_data { + struct fusion_F0710A_info info; + struct i2c_client *client; + struct workqueue_struct *workq; + struct input_dev *input; + u16 x1; + u16 y1; + u8 z1; + u8 tip1; + u8 tid1; + u16 x2; + u16 y2; + u8 z2; + u8 tip2; + u8 tid2; + u8 f_num; + u8 save_points; +}; + diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index ae88e13c99ff..dbd94f3c957a 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -48,17 +48,6 @@ #define STMPE_IRQ_TOUCH_DET 0 -#define SAMPLE_TIME(x) ((x & 0xf) << 4) -#define MOD_12B(x) ((x & 0x1) << 3) -#define REF_SEL(x) ((x & 0x1) << 1) -#define ADC_FREQ(x) (x & 0x3) -#define AVE_CTRL(x) ((x & 0x3) << 6) -#define DET_DELAY(x) ((x & 0x7) << 3) -#define SETTLING(x) (x & 0x7) -#define FRACTION_Z(x) (x & 0x7) -#define I_DRIVE(x) (x & 0x1) -#define OP_MODE(x) ((x & 0x7) << 1) - #define STMPE_TS_NAME "stmpe-ts" #define XY_MASK 0xfff @@ -118,6 +107,7 @@ static void stmpe_work(struct work_struct *work) __stmpe_reset_fifo(ts->stmpe); input_report_abs(ts->idev, ABS_PRESSURE, 0); + input_report_key(ts->idev, BTN_TOUCH, 0); input_sync(ts->idev); } @@ -148,9 +138,17 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data) y = ((data_set[1] & 0xf) << 8) | data_set[2]; z = data_set[3]; +#ifndef CONFIG_ANDROID input_report_abs(ts->idev, ABS_X, x); input_report_abs(ts->idev, ABS_Y, y); +#else /* !CONFIG_ANDROID */ + /* Hack: rotate touch for now due to missing calibration integration + Note: 12-bit touch resolution */ + input_report_abs(ts->idev, ABS_X, 4096 - x); + input_report_abs(ts->idev, ABS_Y, 4096 - y); +#endif /* !CONFIG_ANDROID */ input_report_abs(ts->idev, ABS_PRESSURE, z); + input_report_key(ts->idev, BTN_TOUCH, (z != 0)); input_sync(ts->idev); /* flush the FIFO after we have read out our values. */ @@ -161,7 +159,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data) STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN); /* start polling for touch_det to detect release */ - schedule_delayed_work(&ts->work, HZ / 50); + schedule_delayed_work(&ts->work, HZ / 10); return IRQ_HANDLED; } diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 5dbe73af2f8f..72e2abea2c28 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -54,6 +54,10 @@ #define WM_CORE_VERSION "1.00" #define DEFAULT_PRESSURE 0xb0c0 +#ifdef CONFIG_MACH_COLIBRI_T20 +extern void *get_colibri_t20_audio_platform_data(void); +#endif + /* * Touchscreen absolute values @@ -442,8 +446,18 @@ static int wm97xx_read_samples(struct wm97xx *wm) "pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n", data.x >> 12, data.x & 0xfff, data.y >> 12, data.y & 0xfff, data.p >> 12, data.p & 0xfff); +#ifndef CONFIG_ANDROID input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff); input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff); +#else /* !CONFIG_ANDROID */ + /* Hack: rotate touch for now due to missing calibration + integration + Note: 12-bit touch resolution */ + input_report_abs(wm->input_dev, ABS_X, 4096 - (data.x & 0xfff)); + input_report_abs(wm->input_dev, ABS_Y, 4096 - (data.y & 0xfff)); +#endif /* !CONFIG_ANDROID */ + + input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff); input_report_key(wm->input_dev, BTN_TOUCH, 1); input_sync(wm->input_dev); @@ -640,7 +654,12 @@ static int wm97xx_probe(struct device *dev) } /* set up touch configuration */ +#ifdef CONFIG_ANDROID + /* Hack: rename due to idc parser having issues with spaces in names */ + wm->input_dev->name = "wm97xx-ts"; +#else /* CONFIG_ANDROID */ wm->input_dev->name = "wm97xx touchscreen"; +#endif /* CONFIG_ANDROID */ wm->input_dev->phys = "wm97xx"; wm->input_dev->open = wm97xx_ts_input_open; wm->input_dev->close = wm97xx_ts_input_close; @@ -671,7 +690,13 @@ static int wm97xx_probe(struct device *dev) } platform_set_drvdata(wm->battery_dev, wm); wm->battery_dev->dev.parent = dev; + +#if defined(CONFIG_MACH_COLIBRI_T20) && !defined(CONFIG_ANDROID) + wm->battery_dev->dev.platform_data = get_colibri_t20_audio_platform_data(); +#else wm->battery_dev->dev.platform_data = pdata; +#endif + ret = platform_device_add(wm->battery_dev); if (ret < 0) goto batt_reg_err; diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index dfff30255a92..0fe628f5912d 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -60,7 +60,6 @@ config VIDEOBUF2_VMALLOC select VIDEOBUF2_MEMOPS tristate - config VIDEOBUF2_DMA_SG #depends on HAS_DMA select VIDEOBUF2_CORE @@ -797,6 +796,12 @@ config SOC_CAMERA_IMX074 help This driver supports IMX074 cameras from Sony +config SOC_CAMERA_MAX9526 + tristate "max9526 support" + depends on SOC_CAMERA && I2C + help + This driver supports MAX9526 video decoders from Maxim Integrated + config SOC_CAMERA_MT9M001 tristate "mt9m001 support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index ce79916258ef..28362059e105 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o +obj-$(CONFIG_SOC_CAMERA_MAX9526) += max9526.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c index d2138d06bcad..14b48edb39b2 100644 --- a/drivers/media/video/adv7180.c +++ b/drivers/media/video/adv7180.c @@ -27,13 +27,20 @@ #include <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> +#include <media/soc_camera.h> #include <linux/mutex.h> #define DRIVER_NAME "adv7180" #define ADV7180_INPUT_CONTROL_REG 0x00 +#define ADV7180_INPUT_CONTROL_COMPOSITE_IN1 0x00 +#define ADV7180_INPUT_CONTROL_COMPOSITE_IN2 0x01 +#define ADV7180_INPUT_CONTROL_COMPOSITE_IN3 0x02 +#define ADV7180_INPUT_CONTROL_COMPOSITE_IN4 0x03 +#define ADV7180_INPUT_CONTROL_COMPOSITE_IN5 0x04 +#define ADV7180_INPUT_CONTROL_COMPOSITE_IN6 0x05 #define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00 -#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10 +#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_M_SECAM 0x10 #define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20 #define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30 #define ADV7180_INPUT_CONTROL_NTSC_J 0x40 @@ -71,7 +78,8 @@ #define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 #define ADV7180_IDENT_REG 0x11 -#define ADV7180_ID_7180 0x18 +#define ADV7180_ID_7180 0x1C /* 64-lead and 40-lead models only */ +#define ADV7180_ID2_7180 0x1E /* 48-lead and 32-lead devices only */ #define ADV7180_ICONF1_ADI 0x40 #define ADV7180_ICONF1_ACTIVE_LOW 0x01 @@ -97,6 +105,7 @@ struct adv7180_state { int irq; v4l2_std_id curr_norm; bool autodetect; + int active_input; }; static v4l2_std_id adv7180_std_to_v4l2(u8 status1) @@ -224,14 +233,18 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) if (std == V4L2_STD_ALL) { ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG, - ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM); + ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM | + (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 + + state->active_input)); if (ret < 0) goto out; __adv7180_status(client, NULL, &state->curr_norm); state->autodetect = true; } else { - ret = v4l2_std_to_adv7180(std); + ret = v4l2_std_to_adv7180(std) | + (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 + + state->active_input); if (ret < 0) goto out; @@ -249,19 +262,99 @@ out: return ret; } +static int adv7180_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +/* Request bus settings on camera side */ +static unsigned long adv7180_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + + unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static enum v4l2_mbus_pixelcode adv7180_codes[] = { + V4L2_MBUS_FMT_YUYV8_2X8, +}; + +static int adv7180_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + enum v4l2_colorspace cspace; + enum v4l2_mbus_pixelcode code = mf->code; +// struct i2c_client *client = v4l2_get_subdevdata(sd); +// u8 status1; + +// status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG); +// printk(KERN_ERR "*********************************** status1 = 0x%02x\n", status1); + + switch (code) { + case V4L2_MBUS_FMT_YUYV8_2X8: + cspace = V4L2_COLORSPACE_SRGB; + break; + default: + return -EINVAL; + } + + mf->code = code; + mf->colorspace = cspace; + + return adv7180_s_std(sd, V4L2_STD_ALL); +} + +static int adv7180_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + mf->field = V4L2_FIELD_INTERLACED_TB; + mf->code = V4L2_MBUS_FMT_YUYV8_2X8; + mf->colorspace = V4L2_COLORSPACE_SRGB; + + // PAL + mf->width = 720; + mf->height = 576; + + return 0; +} + +static int adv7180_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(adv7180_codes)) + return -EINVAL; + + *code = adv7180_codes[index]; + + return 0; +} + +static struct soc_camera_ops adv7180_ops = { + .set_bus_param = adv7180_set_bus_param, + .query_bus_param = adv7180_query_bus_param, +}; + static const struct v4l2_subdev_video_ops adv7180_video_ops = { - .querystd = adv7180_querystd, - .g_input_status = adv7180_g_input_status, + .s_mbus_fmt = adv7180_s_fmt, + .try_mbus_fmt = adv7180_try_fmt, + .enum_mbus_fmt = adv7180_enum_fmt, + .querystd = adv7180_querystd, + .g_input_status = adv7180_g_input_status, }; static const struct v4l2_subdev_core_ops adv7180_core_ops = { - .g_chip_ident = adv7180_g_chip_ident, - .s_std = adv7180_s_std, + .g_chip_ident = adv7180_g_chip_ident, + .s_std = adv7180_s_std, }; -static const struct v4l2_subdev_ops adv7180_ops = { - .core = &adv7180_core_ops, - .video = &adv7180_video_ops, +static const struct v4l2_subdev_ops adv7180_subdev_ops = { + .core = &adv7180_core_ops, + .video = &adv7180_video_ops, }; static void adv7180_work(struct work_struct *work) @@ -297,6 +390,36 @@ static irqreturn_t adv7180_irq(int irq, void *devid) return IRQ_HANDLED; } +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { + struct soc_camera_device *icd = file->private_data; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct adv7180_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 val; + + if (i < 6) { + state->active_input = i; + val = i2c_smbus_read_byte_data(client, + ADV7180_INPUT_CONTROL_REG); + val &= 0xf0; + val |= (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 + + state->active_input); + return i2c_smbus_write_byte_data(client, + ADV7180_INPUT_CONTROL_REG, val); + } + return -EINVAL; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { + struct soc_camera_device *icd = file->private_data; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct adv7180_state *state = to_state(sd); + + *i = state->active_input; + + return 0; +} + /* * Generic i2c probe * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' @@ -306,8 +429,11 @@ static __devinit int adv7180_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adv7180_state *state; + struct soc_camera_device *icd = client->dev.platform_data; struct v4l2_subdev *sd; + u8 ident; int ret; + struct v4l2_ioctl_ops *ops; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -322,17 +448,25 @@ static __devinit int adv7180_probe(struct i2c_client *client, goto err; } + ident = i2c_smbus_read_byte_data(client, ADV7180_IDENT_REG); + WARN_ON((ident != ADV7180_ID_7180) && (ident != ADV7180_ID2_7180)); + v4l_info(client, "ident reg is 0x%02x\n", ident); + state->irq = client->irq; INIT_WORK(&state->work, adv7180_work); mutex_init(&state->mutex); state->autodetect = true; + state->active_input = 0; // input 1 sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &adv7180_ops); + v4l2_i2c_subdev_init(sd, client, &adv7180_subdev_ops); + icd->ops = &adv7180_ops; /* Initialize adv7180 */ /* Enable autodetection */ ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG, - ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM); + ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM | + (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 + + state->active_input)); if (ret < 0) goto err_unreg_subdev; @@ -393,6 +527,15 @@ static __devinit int adv7180_probe(struct i2c_client *client, goto err_unreg_subdev; } + /* + * this is the only way to support more than one input as soc_camera + * assumes in its own vidioc_s(g)_input implementation that only one + * input is present we have to override that with our own handlers. + */ + ops = (struct v4l2_ioctl_ops*)icd->vdev->ioctl_ops; + ops->vidioc_s_input = &vidioc_s_input; + ops->vidioc_g_input = &vidioc_g_input; + return 0; err_unreg_subdev: @@ -432,7 +575,7 @@ static const struct i2c_device_id adv7180_id[] = { {}, }; -MODULE_DEVICE_TABLE(i2c, adv7180_id); +//MODULE_DEVICE_TABLE(i2c, adv7180_id); static struct i2c_driver adv7180_driver = { .driver = { @@ -460,4 +603,3 @@ module_exit(adv7180_exit); MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); MODULE_AUTHOR("Mocean Laboratories"); MODULE_LICENSE("GPL v2"); - diff --git a/drivers/media/video/max9526.c b/drivers/media/video/max9526.c new file mode 100644 index 000000000000..1f13dcb29c5a --- /dev/null +++ b/drivers/media/video/max9526.c @@ -0,0 +1,1102 @@ +/* + * drivers/media/video/max9526.c + * + * MAXIM MAX9526 decoder driver + * + * Copyright (c) 2011 Ming-Yao Chen <mychen0518@gmail.com> + * (based on tvp514x.c) + * + * Copyright (c) 2013 Ant Micro <www.antmicro.com> + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/videodev2.h> + +#include <media/soc_camera.h> +#include <media/v4l2-device.h> +#include <media/v4l2-common.h> +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-ioctl.h> + +/*MODULE NAME*/ +#define MAX9526_MODULE_NAME "max9526" + +/*Private macros for MAX9526*/ + +#define LOCK_RETRY_DELAY (200) +#define LOCK_RETRY_COUNT (5) +#define I2C_RETRY_COUNT (5) + + + /* registers */ +#define REG_STATUS_0 0x00 +#define REG_STATUS_1 0x01 +#define REG_IRQMASK_0 0x02 +#define REG_IRQMASK_1 0x03 +#define REG_STANDARD_SELECT_SHUTDOWN_CONTROL 0x04 +#define REG_CONTRAST 0x05 +#define REG_BRIGHTNESS 0x06 +#define REG_HUE 0x07 +#define REG_SATURATION 0x08 +#define REG_VIDEO_INPUT_SELECT_AND_CLAMP 0x09 +#define REG_GAIN_CONTROL 0x0A +#define REG_COLOR_KILL 0x0B +#define REG_OUTPUT_TEST_SIGNAL 0x0C +#define REG_CLOCK_AND_OUTPUT 0x0D +#define REG_PLL_CONTROL 0x0E +#define REG_MISCELLANEOUS 0x0F + +#define PAL_NUM_ACTIVE_PIXELS (720) +#define PAL_NUM_ACTIVE_LINES (576) + +#define NTSC_NUM_ACTIVE_PIXELS (720) +#define NTSC_NUM_ACTIVE_LINES (480) + +#define REG_VIDEO_INPUT_SELECT_IN1 0x00 +#define REG_VIDEO_INPUT_SELECT_IN2 0x40 +#define REG_VIDEO_INPUT_SELECT_AUTO 0x80 + + +struct max9526_reg { + u8 token; + u8 reg; + u32 val; +}; + +enum max9526_tokens { + TOK_TERM, + TOK_SKIP, + TOK_DELAY, + TOK_WRITE, +}; + +enum { + VIDEO_STDSEL_NTSC_M_BIT, + VIDEO_STDSEL_PAL_BGHID_BIT, +}; + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("MAX9526 linux decoder driver"); +MODULE_LICENSE("GPL"); + + +/* enum max9526_std - enum for supported standards*/ + +enum max9526_std { + STD_NTSC_MJ = 0, + STD_PAL_BDGHIN, + STD_INVALID +}; + + +/** + * struct max9526_std_info - Structure to store standard informations + * @width: Line width in pixels + * @height:Number of active lines + * @video_std: Value to write in REG_VIDEO_STD register + * @standard: v4l2 standard structure information + */ + + +struct max9526_std_info { + unsigned long width; + unsigned long height; + u8 video_std; + struct v4l2_standard standard; +}; + +// TODO: redo this +static const struct max9526_reg max9526_reg_list_default[] = { + {TOK_SKIP , REG_STATUS_0, 0x84}, + {TOK_SKIP , REG_STATUS_1, 0x40}, + {TOK_SKIP , REG_IRQMASK_0, 0x00}, + {TOK_SKIP , REG_IRQMASK_1, 0x00}, + /*Standard Select, Shutdown, and Control Register*/ + {TOK_WRITE, REG_STANDARD_SELECT_SHUTDOWN_CONTROL, 0x10}, // was 0x10 (autodetect), 0x0=PAL, 0x40=NTSC + {TOK_SKIP, REG_CONTRAST, 0x80}, + {TOK_SKIP, REG_BRIGHTNESS, 0x00}, + {TOK_SKIP, REG_HUE, 0x80}, + {TOK_SKIP, REG_SATURATION, 0x88}, + {TOK_WRITE, REG_VIDEO_INPUT_SELECT_AND_CLAMP, 0x80}, // auto-select + // between input 1 and 2 + {TOK_SKIP, REG_GAIN_CONTROL, 0x00}, + {TOK_SKIP, REG_COLOR_KILL, 0x23}, + {TOK_WRITE, REG_OUTPUT_TEST_SIGNAL, 0x03}, // select 100% color bars + {TOK_WRITE, REG_CLOCK_AND_OUTPUT, 0x04}, // select HSVS + {TOK_SKIP, REG_PLL_CONTROL, 0x03}, + {TOK_SKIP, REG_MISCELLANEOUS, 0x18}, + {TOK_TERM, 0, 0}, +}; + + +//static struct max9526_reg max9526_reg_list_default[0x11]; + +/*MAX9526 default register values*/ + +static int max9526_s_stream(struct v4l2_subdev *sd, int enable); + +/** + * struct max9526_decoder - MAX9526 decoder object + * @sd: Subdevice Slave handle + * @max9526_regs: copy of hw's regs with preset values. + * @pdata: Board specific + * @ver: Chip version + * @streaming: MAX9526 decoder streaming - enabled or disabled. + * @pix: Current pixel format + * @num_fmts: Number of formats + * @fmt_list: Format list + * @current_std: Current standard + * @num_stds: Number of standards + * @std_list: Standards list + * @input: Input routing at chip level + * @output: Output routing at chip level + */ +struct max9526_decoder { + struct v4l2_subdev sd; + struct max9526_reg max9526_regs[ARRAY_SIZE(max9526_reg_list_default)]; + const struct max9526_platform_data *pdata; + + int ver; + int streaming; + + struct v4l2_pix_format pix; + int num_fmts; + const struct v4l2_fmtdesc *fmt_list; + + enum max9526_std current_std; + int num_stds; + struct max9526_std_info *std_list; + /* Input and Output Routing parameters */ + u32 input; + u32 output; + + int active_input; +}; + +/** + * List of image formats supported by max9526 decoder + * Currently we are using 8 bit mode only, but can be + * extended to 10/20 bit mode. + */ +static const struct v4l2_fmtdesc max9526_fmt_list[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = 0, + .description = "8-bit YUYV 4:2:2 Format", + .pixelformat = V4L2_PIX_FMT_YUYV, + }, + { + .index = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = 0, + .description = "8-bit UYVY 4:2:2 Format", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, +}; + +/** + * Supported standards - + * + * Currently supports two standards only, need to add support for rest of the + * modes, like SECAM, etc... + */ +static struct max9526_std_info max9526_std_list[] = { + /* Standard: STD_NTSC_MJ */ + [STD_NTSC_MJ] = { + .width = NTSC_NUM_ACTIVE_PIXELS, + .height = NTSC_NUM_ACTIVE_LINES, + .video_std = VIDEO_STDSEL_NTSC_M_BIT, + .standard = { + .index = 0, + .id = V4L2_STD_NTSC, + .name = "NTSC", + .frameperiod = {1001, 30000}, + .framelines = 525 + }, + /* Standard: STD_PAL_BDGHIN */ + }, + [STD_PAL_BDGHIN] = { + .width = PAL_NUM_ACTIVE_PIXELS, + .height = PAL_NUM_ACTIVE_LINES, + .video_std = VIDEO_STDSEL_PAL_BGHID_BIT, + .standard = { + .index = 1, + .id = V4L2_STD_PAL, + .name = "PAL", + .frameperiod = {1, 25}, + .framelines = 625 + }, + }, + /* Standard: need to add for additional standard */ +}; + +static inline struct max9526_decoder *to_decoder(struct v4l2_subdev *sd) +{ + return container_of(sd, struct max9526_decoder, sd); +} + +/** + * max9526_read_reg() - Read a value from a register in an MAX9526. + * @sd: ptr to v4l2_subdev struct + * @reg: max9526 register address + * + * Returns value read if successful, or non-zero (-1) otherwise. + */ +static int max9526_read_reg(struct v4l2_subdev *sd, u8 reg) +{ + int err, retry = 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); + +read_again: + + err = i2c_smbus_read_byte_data(client, reg); + if (err < 0) { + if (retry <= I2C_RETRY_COUNT) { + v4l2_warn(sd, "Read: retry ... %d\n", retry); + retry++; + msleep_interruptible(10); + goto read_again; + } + } + + return err; +} + +#if 0 +/** + * dump_reg() - dump the register content of MAX9526. + * @sd: ptr to v4l2_subdev struct + * @reg: MAX9526 register address + */ +static void dump_reg(struct v4l2_subdev *sd, u8 reg) +{ + u32 val; + + val = max9526_read_reg(sd, reg); + v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val); +} +#endif + +/** + * max9526_write_reg() - Write a value to a register in MAX9526 + * @sd: ptr to v4l2_subdev struct + * @reg: MAX9526 register address + * @val: value to be written to the register + * + * Write a value to a register in an MAX9526 decoder device. + * Returns zero if successful, or non-zero otherwise. + */ +static int max9526_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + int err, retry = 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); +write_again: + + err = i2c_smbus_write_byte_data(client, reg, val); + if (err) { + if (retry <= I2C_RETRY_COUNT) { + v4l2_warn(sd, "Write: retry ... %d\n", retry); + retry++; + msleep_interruptible(10); + goto write_again; + } + } +// if (!err) { +// v4l2_warn(sd, "max9526: wrote %X to register %X.\n", val, reg); +// } + return err; +} + + +/** + * max9526_write_regs() : Initializes a list of MAX9526 registers + * @sd: ptr to v4l2_subdev struct + * @reglist: list of MAX9526 registers and values + * + * Initializes a list of MAX9526 registers: token is state flag + * if token is TOK_TERM, then entire write operation terminates + * if token is TOK_DELAY, then a delay of 'val' msec is introduced + * if token is TOK_SKIP, then the register write is skipped + * if token is TOK_WRITE, then the register write is performed + * Returns zero if successful, or non-zero otherwise. + */ +static int max9526_write_regs(struct v4l2_subdev *sd, + const struct max9526_reg reglist[]) +{ + int err; + const struct max9526_reg *next = reglist; + for (; next->token != TOK_TERM; next++) { + if (next->token == TOK_DELAY) { + msleep(next->val); + continue; + } + + if (next->token == TOK_SKIP) + continue; + + err = max9526_write_reg(sd, next->reg, (u8) next->val); + if (err) { + v4l2_err(sd, "Write failed. Err[%d]\n", err); + return err; + } + } + return 0; +} + + +/** + * max9526_get_current_std() : Get the current standard detected by max9526 + * @sd: ptr to v4l2_subdev struct + * + * Get current standard detected by MAX9526, STD_INVALID if there is no + * standard detected. + */ +static enum max9526_std max9526_get_current_std(struct v4l2_subdev *sd) +{ + u8 std, std_status; + + std = max9526_read_reg(sd, REG_STANDARD_SELECT_SHUTDOWN_CONTROL); + + std_status = std>>5; + switch (std_status) { + case VIDEO_STDSEL_NTSC_M_BIT: + return STD_NTSC_MJ; + + case VIDEO_STDSEL_PAL_BGHID_BIT: + return STD_PAL_BDGHIN; + + default: + return STD_INVALID; + } + + return STD_INVALID; +} + + +/** + * max9526_configure() - Configure the MAX9526 registers + * @sd: ptr to v4l2_subdev struct + * @decoder: ptr to max9526_decoder structure + * + * Returns zero if successful, or non-zero otherwise. + */ +static int max9526_configure(struct v4l2_subdev *sd, struct max9526_decoder *decoder) +{ + int err; + + /* common register initialization */ + err = + max9526_write_regs(sd, decoder->max9526_regs); + if (err) + return err; + +// if (debug) +// max9526_reg_dump(sd); + + return 0; +} + + +/** + * max9526_querystd() - V4L2 decoder interface handler for querystd + * @sd: pointer to standard V4L2 sub-device structure + * @std_id: standard V4L2 std_id ioctl enum + * + * Returns the current standard detected by MAX9526. If no active input is + * detected, returns -EINVAL + */ +static int max9526_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) +{ + struct max9526_decoder *decoder = to_decoder(sd); + enum max9526_std current_std; + //enum max9526_input input_sel; + //u8 sync_lock_status, lock_mask; + //int err; + + if (std_id == NULL) + return -EINVAL; + + msleep(LOCK_RETRY_DELAY); + + /* get the current standard */ + current_std = max9526_get_current_std(sd); + if (current_std == STD_INVALID) + return -EINVAL; + + decoder->current_std = current_std; + *std_id = decoder->std_list[current_std].standard.id; + +// v4l2_dbg(1, debug, sd, "Current STD: %s", +// decoder->std_list[current_std].standard.name); + return 0; +} + +/** + * max9526_s_std() - V4L2 decoder interface handler for s_std + * @sd: pointer to standard V4L2 sub-device structure + * @std_id: standard V4L2 v4l2_std_id ioctl enum + * + * If std_id is supported, sets the requested standard. Otherwise, returns + * -EINVAL + */ +static int max9526_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id) +{ + struct max9526_decoder *decoder = to_decoder(sd); + int err, i; + + for (i = 0; i < decoder->num_stds; i++) + if (std_id & decoder->std_list[i].standard.id) + break; + + if ((i == decoder->num_stds) || (i == STD_INVALID)) + return -EINVAL; + + err = max9526_write_reg(sd, REG_STANDARD_SELECT_SHUTDOWN_CONTROL, + decoder->std_list[i].video_std); + if (err) + return err; + + decoder->current_std = i; + decoder->max9526_regs[REG_STANDARD_SELECT_SHUTDOWN_CONTROL].val = + decoder->std_list[i].video_std; + +// v4l2_dbg(1, debug, sd, "Standard set to: %s", +// decoder->std_list[i].standard.name); + return 0; +} + +/** + * max9526_s_routing() - V4L2 decoder interface handler for s_routing + * @sd: pointer to standard V4L2 sub-device structure + * @input: input selector for routing the signal + * @output: output selector for routing the signal + * @config: config value. Not used + * + * If index is valid, selects the requested input. Otherwise, returns -EINVAL if + * the input is not supported or there is no active signal present in the + * selected input. + */ +static int max9526_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + //struct max9526_decoder *decoder = to_decoder(sd); + + /* + * For the sequence streamon -> streamoff and again s_input, most of + * the time it fails to lock the signal, since streamoff puts MAX9526 + * into power off state which leads to failure in sub-sequent s_input. + */ + max9526_s_stream(sd, 1); + return 0; +} + + +/** + * max9526_queryctrl() - V4L2 decoder interface handler for queryctrl + * @sd: pointer to standard V4L2 sub-device structure + * @qctrl: standard V4L2 v4l2_queryctrl structure + * + * If the requested control is supported, returns the control information. + * Otherwise, returns -EINVAL if the control is not supported. + */ +static int +max9526_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) +{ + int err = -EINVAL; + + if (qctrl == NULL) + return err; + + switch (qctrl->id) { + case V4L2_CID_BRIGHTNESS: + /* Brightness supported is (0-255), */ + err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); + break; + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + /** + * Saturation and Contrast supported is - + * Contrast: 0 - 255 (Default - 128) + * Saturation: 0 - 255 (Default - 128) + */ + err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); + break; + case V4L2_CID_HUE: + /* Hue Supported is - + * Hue - -180 - +180 (Default - 0, Step - +180) + */ + err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0); + break; + case V4L2_CID_AUTOGAIN: + /** + * Auto Gain supported is - + * 0 - 1 (Default - 1) + */ + err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); + break; + default: + v4l2_err(sd, "invalid control id %d\n", qctrl->id); + return err; + } + +// v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d", +// qctrl->name, qctrl->minimum, qctrl->maximum, +// qctrl->default_value); + + return err; +} + + +/** + * max9526_g_ctrl() - V4L2 decoder interface handler for g_ctrl + * @sd: pointer to standard V4L2 sub-device structure + * @ctrl: pointer to v4l2_control structure + * + * If the requested control is supported, returns the control's current + * value from the decoder. Otherwise, returns -EINVAL if the control is not + * supported. + */ +static int +max9526_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct max9526_decoder *decoder = to_decoder(sd); + + if (ctrl == NULL) + return -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = decoder->max9526_regs[REG_BRIGHTNESS].val; + break; + case V4L2_CID_CONTRAST: + ctrl->value = decoder->max9526_regs[REG_CONTRAST].val; + break; + case V4L2_CID_SATURATION: + ctrl->value = decoder->max9526_regs[REG_SATURATION].val; + break; + case V4L2_CID_HUE: + ctrl->value = decoder->max9526_regs[REG_HUE].val; + if (ctrl->value == 0x7F) + ctrl->value = 180; + else if (ctrl->value == 0x80) + ctrl->value = -180; + else + ctrl->value = 0; + + break; + default: + v4l2_err(sd, "invalid control id %d\n", ctrl->id); + return -EINVAL; + } + +// v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d", +// ctrl->id, ctrl->value); + return 0; +} + +/** + * max9526_s_ctrl() - V4L2 decoder interface handler for s_ctrl + * @sd: pointer to standard V4L2 sub-device structure + * @ctrl: pointer to v4l2_control structure + * + * If the requested control is supported, sets the control's current + * value in HW. Otherwise, returns -EINVAL if the control is not supported. + */ +static int +max9526_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct max9526_decoder *decoder = to_decoder(sd); + int err = -EINVAL, value; + + if (ctrl == NULL) + return err; + + value = ctrl->value; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + if (ctrl->value < 0 || ctrl->value > 255) { + v4l2_err(sd, "invalid brightness setting %d\n", + ctrl->value); + return -ERANGE; + } + err = max9526_write_reg(sd, REG_BRIGHTNESS, + value); + if (err) + return err; + + decoder->max9526_regs[REG_BRIGHTNESS].val = value; + break; + case V4L2_CID_CONTRAST: + if (ctrl->value < 0 || ctrl->value > 255) { + v4l2_err(sd, "invalid contrast setting %d\n", + ctrl->value); + return -ERANGE; + } + err = max9526_write_reg(sd, REG_CONTRAST, value); + if (err) + return err; + + decoder->max9526_regs[REG_CONTRAST].val = value; + break; + case V4L2_CID_SATURATION: + if (ctrl->value < 0 || ctrl->value > 255) { + v4l2_err(sd, "invalid saturation setting %d\n", + ctrl->value); + return -ERANGE; + } + err = max9526_write_reg(sd, REG_SATURATION, value); + if (err) + return err; + + decoder->max9526_regs[REG_SATURATION].val = value; + break; + case V4L2_CID_HUE: + if (value == 180) + value = 0x7F; + else if (value == -180) + value = 0x80; + else if (value == 0) + value = 0; + else { + v4l2_err(sd, "invalid hue setting %d\n", ctrl->value); + return -ERANGE; + } + err = max9526_write_reg(sd, REG_HUE, value); + if (err) + return err; + + decoder->max9526_regs[REG_HUE].val = value; + break; + default: + v4l2_err(sd, "invalid control id %d\n", ctrl->id); + return err; + } + +// v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d", +// ctrl->id, ctrl->value); + + return err; +} + + +static int max9526_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + struct max9526_decoder *decoder = to_decoder(sd); + + if (index < 0 || index >= decoder->num_fmts) + return -EINVAL; + switch (index) { + case 0: + *code = V4L2_MBUS_FMT_YUYV8_2X8; + break; + case 1: + *code = V4L2_MBUS_FMT_UYVY8_2X8; + break; + default: + return -EINVAL; + } + return 0; +} + +static int max9526_try_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ +/* pr_info("%s width:%d\n", __func__, mf->width); + pr_info("%s height:%d\n", __func__, mf->height); + pr_info("%s field:0x%X (V4L2_FIELD_NONE==0x%X)\n", __func__, mf->field, V4L2_FIELD_NONE); + pr_info("%s code:0x%X (V4L2_MBUS_FMT_YUYV8_2X8==0x%X)\n", __func__, mf->code, V4L2_MBUS_FMT_YUYV8_2X8); + pr_info("%s colorspace:0x%X (V4L2_COLORSPACE_SRGB==0x%X)\n", __func__, mf->colorspace, V4L2_COLORSPACE_SRGB);*/ + + if (mf->code == V4L2_MBUS_FMT_UYVY8_2X8) { + mf->width = PAL_NUM_ACTIVE_PIXELS; + mf->height = PAL_NUM_ACTIVE_LINES; + } else if (mf->code == V4L2_MBUS_FMT_YUYV8_2X8) { + mf->width = PAL_NUM_ACTIVE_PIXELS; + mf->height = PAL_NUM_ACTIVE_LINES; + } + mf->field = V4L2_FIELD_INTERLACED_TB; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + + return 0; +} + + +/** + * max9526_g_parm() - V4L2 decoder interface handler for g_parm + * @sd: pointer to standard V4L2 sub-device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the decoder's video CAPTURE parameters. + */ +static int +max9526_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct max9526_decoder *decoder = to_decoder(sd); + struct v4l2_captureparm *cparm; + enum max9526_std current_std; + + if (a == NULL) + return -EINVAL; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + /* only capture is supported */ + return -EINVAL; + + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* get the current standard */ + current_std = max9526_get_current_std(sd); + if (current_std == STD_INVALID) + return -EINVAL; + + decoder->current_std = current_std; + + cparm = &a->parm.capture; + cparm->capability = V4L2_CAP_TIMEPERFRAME; + cparm->timeperframe = + decoder->std_list[current_std].standard.frameperiod; + + return 0; +} + + +/** + * max9526_s_parm() - V4L2 decoder interface handler for s_parm + * @sd: pointer to standard V4L2 sub-device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the decoder to use the input parameters, if possible. If + * not possible, returns the appropriate error code. + */ +static int +max9526_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct max9526_decoder *decoder = to_decoder(sd); + struct v4l2_fract *timeperframe; + enum max9526_std current_std; + + if (a == NULL) + return -EINVAL; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + /* only capture is supported */ + return -EINVAL; + + timeperframe = &a->parm.capture.timeperframe; + + /* get the current standard */ + current_std = max9526_get_current_std(sd); + if (current_std == STD_INVALID) + return -EINVAL; + + decoder->current_std = current_std; + + *timeperframe = + decoder->std_list[current_std].standard.frameperiod; + + return 0; +} + +/** + * max9526_s_stream() - V4L2 decoder i/f handler for s_stream + * @sd: pointer to standard V4L2 sub-device structure + * @enable: streaming enable or disable + * + * Sets streaming to enable or disable, if possible. + */ +static int max9526_s_stream(struct v4l2_subdev *sd, int enable) +{ + int err = 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct max9526_decoder *decoder = to_decoder(sd); + + if (decoder->streaming == enable) + return 0; + + switch (enable) { + case 0: + { + decoder->streaming = enable; + break; + } + case 1: + { + struct max9526_reg *int_seq = (struct max9526_reg *)client->driver->id_table->driver_data; + + err = max9526_write_regs(sd, int_seq); + if (err) { + v4l2_err(sd, "Unable to turn on decoder\n"); + return err; + } + err = max9526_configure(sd, decoder); + if (err) { + v4l2_err(sd, "Unable to configure decoder\n"); + return err; + } + decoder->streaming = enable; + break; + } + default: + err = -ENODEV; + break; + } + + return err; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { + struct soc_camera_device *icd = file->private_data; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct max9526_decoder *decoder = to_decoder(sd); + u8 val; + + if (i < 3) { + decoder->active_input = i; + switch (decoder->active_input) { + case 0: + val = REG_VIDEO_INPUT_SELECT_IN1; + break; + case 1: + val = REG_VIDEO_INPUT_SELECT_IN2; + break; + default: + val = REG_VIDEO_INPUT_SELECT_AUTO; + } + return max9526_write_reg(sd, REG_VIDEO_INPUT_SELECT_AND_CLAMP, + val); + } + + return -EINVAL; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { + struct soc_camera_device *icd = file->private_data; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct max9526_decoder *decoder = to_decoder(sd); + + *i = decoder->active_input; + + return 0; +} + +static const struct v4l2_subdev_core_ops max9526_core_ops = { + .queryctrl = max9526_queryctrl, + .g_ctrl = max9526_g_ctrl, + .s_ctrl = max9526_s_ctrl, + .s_std = max9526_s_std, +}; + + +static int max9526_s_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ +#if 0 + pr_info("%s width:%d\n", __func__, mf->width); + pr_info("%s height:%d\n", __func__, mf->height); + pr_info("%s field:0x%X (V4L2_FIELD_NONE==0x%X)\n", __func__, mf->field, V4L2_FIELD_NONE); + pr_info("%s code:0x%X (V4L2_MBUS_FMT_YUYV8_2X8==0x%X)\n", __func__, mf->code, V4L2_MBUS_FMT_YUYV8_2X8); + pr_info("%s colorspace:0x%X (V4L2_COLORSPACE_SRGB==0x%X)\n", __func__, mf->colorspace, V4L2_COLORSPACE_SRGB); + + mf->width = PAL_NUM_ACTIVE_PIXELS; + mf->height = PAL_NUM_ACTIVE_LINES; + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; +#endif + return 0; +} + +static const struct v4l2_subdev_video_ops max9526_video_ops = { + .s_routing = max9526_s_routing, + .querystd = max9526_querystd, + .enum_mbus_fmt = max9526_enum_mbus_fmt, + .try_mbus_fmt = max9526_try_mbus_fmt, + .s_mbus_fmt = max9526_s_mbus_fmt, + .g_parm = max9526_g_parm, + .s_parm = max9526_s_parm, + .s_stream = max9526_s_stream, +}; + +/* Alter bus settings on camera side */ +static int max9526_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +static unsigned long max9526_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + + unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static struct soc_camera_ops max9526_soc_camera_ops = { + .set_bus_param = max9526_set_bus_param, + .query_bus_param = max9526_query_bus_param, + .num_controls = 0, +}; + +static const struct v4l2_subdev_ops max9526_ops = { + .core = &max9526_core_ops, + .video = &max9526_video_ops, +}; + +static struct max9526_decoder max9526_dev = { + .streaming = 0, + + .fmt_list = max9526_fmt_list, + .num_fmts = ARRAY_SIZE(max9526_fmt_list), + + .pix = { + /* Default to PAL 8-bit YUV 422 */ + .width = PAL_NUM_ACTIVE_PIXELS, + .height = PAL_NUM_ACTIVE_LINES, + .pixelformat = V4L2_PIX_FMT_UYVY, + .field = V4L2_FIELD_INTERLACED_TB, + .bytesperline = PAL_NUM_ACTIVE_PIXELS * 2, + .sizeimage = + PAL_NUM_ACTIVE_PIXELS * 2 * PAL_NUM_ACTIVE_LINES, + .colorspace = V4L2_COLORSPACE_SMPTE170M, + }, + + .current_std = STD_PAL_BDGHIN, + .std_list = max9526_std_list, + .num_stds = ARRAY_SIZE(max9526_std_list), + + .active_input = 2, // auto-select between input 1 and 2 +}; + +/** + * max9526_probe() - decoder driver i2c probe handler + * @client: i2c driver client device structure + * @id: i2c driver id table + * + * Register decoder as an i2c client device and V4L2 + * device. + */ + +static int max9526_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct max9526_decoder *decoder; + struct v4l2_subdev *sd; + struct soc_camera_device *icd = client->dev.platform_data; + struct v4l2_ioctl_ops *ops; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + if (!client->dev.platform_data) { + v4l2_err(client, "No platform data!!\n"); + return -ENODEV; + } + + decoder = kzalloc(sizeof(*decoder), GFP_KERNEL); + if (!decoder) + return -ENOMEM; + + /* Initialize the max9526_decoder with default configuration */ + *decoder = max9526_dev; + /* Copy default register configuration */ + memcpy(decoder->max9526_regs, max9526_reg_list_default, + sizeof(max9526_reg_list_default)); + + /* Copy board specific information here */ + decoder->pdata = client->dev.platform_data; + + + /* Register with V4L2 layer as slave device */ + sd = &decoder->sd; + v4l2_i2c_subdev_init(sd, client, &max9526_ops); + + icd->ops = &max9526_soc_camera_ops; + + /* + * This is the only way to support more than one input as soc_camera + * assumes in its own vidioc_s(g)_input implementation that only one + * input is present we have to override that with our own handlers. + */ + ops = (struct v4l2_ioctl_ops*)icd->vdev->ioctl_ops; + ops->vidioc_s_input = &vidioc_s_input; + ops->vidioc_g_input = &vidioc_g_input; + + v4l2_info(sd, "%s decoder driver registered !!\n", sd->name); + + return 0; + +} + + +/** + * max9526_remove() - decoder driver i2c remove handler + * @client: i2c driver client device structure + * + * Unregister decoder as an i2c client device and V4L2 + * device. Complement of max9526_probe(). + */ +static int max9526_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct max9526_decoder *decoder = to_decoder(sd); + + v4l2_device_unregister_subdev(sd); + kfree(decoder); + return 0; +} + +/** + * I2C Device Table - + * + * name - Name of the actual device/chip. + * driver_data - Driver data + */ +static const struct i2c_device_id max9526_id[] = { + {"max9526", (unsigned long)max9526_reg_list_default}, +}; + + +static struct i2c_driver max9526_driver = { + .driver = { + .owner = THIS_MODULE, + .name = MAX9526_MODULE_NAME, + }, + .probe = max9526_probe, + .remove = max9526_remove, + .id_table = max9526_id, +}; + +static int __init max9526_init(void) +{ + return i2c_add_driver(&max9526_driver); +} + +static void __exit max9526_exit(void) +{ + i2c_del_driver(&max9526_driver); +} + +module_init(max9526_init); +module_exit(max9526_exit); diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c index 8f71d1702537..14a74cd6b7cc 100644 --- a/drivers/media/video/tegra_v4l2_camera.c +++ b/drivers/media/video/tegra_v4l2_camera.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -14,7 +14,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -23,13 +22,14 @@ #include <linux/nvhost.h> #include <mach/iomap.h> -#include <mach/powergate.h> #include <media/soc_camera.h> #include <media/soc_mediabus.h> #include <media/videobuf2-dma-nvmap.h> #include <media/tegra_v4l2_camera.h> +#include <mach/powergate.h> + #include "dev.h" #include "bus_client.h" #include "host1x/host1x_syncpt.h" @@ -37,18 +37,22 @@ #define TEGRA_CAM_DRV_NAME "vi" #define TEGRA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) -#define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 200 +static unsigned int internal_sync = 0; +module_param(internal_sync, int, 0644); +MODULE_PARM_DESC(internal_sync, "enable internal vsync and hsync decoded " \ + "from data"); + +#define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 25 #define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT 200 #define TEGRA_SYNCPT_RETRY_COUNT 10 -#define TEGRA_VIP_H_ACTIVE_START 0x98 -#define TEGRA_VIP_V_ACTIVE_START 0x10 +#define TEGRA_VIP_H_ACTIVE_START 0x8F //0x98 +#define TEGRA_VIP_V_ACTIVE_START 0x12 //0x10 /* SYNCPTs 12-17 are reserved for VI. */ #define TEGRA_VI_SYNCPT_VI NVSYNCPT_VI_ISP_2 -#define TEGRA_VI_SYNCPT_CSI_A NVSYNCPT_VI_ISP_3 -#define TEGRA_VI_SYNCPT_CSI_B NVSYNCPT_VI_ISP_4 +#define TEGRA_VI_SYNCPT_CSI NVSYNCPT_VI_ISP_3 /* Tegra CSI-MIPI registers. */ #define TEGRA_VI_OUT_1_INCR_SYNCPT 0x0000 @@ -235,7 +239,10 @@ #define TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME 0x08c8 #define TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME 0x08cc #define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x08d0 -#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x08d4 + +#define IS_INTERLACED ((pcdev->field == V4L2_FIELD_INTERLACED)\ + || (pcdev->field == V4L2_FIELD_INTERLACED_BT)\ + || (pcdev->field == V4L2_FIELD_INTERLACED_TB)) #define TC_VI_REG_RD(DEV, REG) readl(DEV->vi_base + REG) #define TC_VI_REG_WT(DEV, REG, VAL) writel(VAL, DEV->vi_base + REG) @@ -256,8 +263,6 @@ struct tegra_buffer { struct vb2_buffer vb; /* v4l buffer must be first */ struct list_head queue; - struct soc_camera_device *icd; - int output_channel; /* * Various buffer addresses shadowed so we don't have to recalculate @@ -269,21 +274,20 @@ struct tegra_buffer { dma_addr_t start_addr; dma_addr_t start_addr_u; dma_addr_t start_addr_v; + void* virtual_addr; }; struct tegra_camera_dev { struct soc_camera_host ici; + struct soc_camera_device *icd; struct nvhost_device *ndev; + struct tegra_camera_platform_data *pdata; struct clk *clk_vi; struct clk *clk_vi_sensor; struct clk *clk_csi; struct clk *clk_isp; struct clk *clk_csus; - struct clk *clk_sclk; - struct clk *clk_emc; - - struct regulator *reg; void __iomem *vi_base; spinlock_t videobuf_queue_lock; @@ -291,22 +295,16 @@ struct tegra_camera_dev { struct vb2_buffer *active; struct vb2_alloc_ctx *alloc_ctx; enum v4l2_field field; - int sequence_a; - int sequence_b; + int sequence; struct work_struct work; struct mutex work_mutex; u32 syncpt_vi; - u32 syncpt_csi_a; - u32 syncpt_csi_b; + u32 syncpt_csi; /* Debug */ int num_frames; - int enable_refcnt; - - /* CSI pad calibration flag */ - int cal_done; }; static const struct soc_mbus_pixelfmt tegra_camera_formats[] = { @@ -352,23 +350,6 @@ static const struct soc_mbus_pixelfmt tegra_camera_formats[] = { .packing = SOC_MBUS_PACKING_NONE, .order = SOC_MBUS_ORDER_LE, }, - - /* For RAW8 and RAW10 output, we always output 16-bit (2 bytes). */ - { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .name = "Bayer 8 BGBG.. GRGR..", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGBG.. GRGR..", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - }, - }; static struct tegra_buffer *to_tegra_vb(struct vb2_buffer *vb) @@ -378,13 +359,9 @@ static struct tegra_buffer *to_tegra_vb(struct vb2_buffer *vb) static void tegra_camera_save_syncpts(struct tegra_camera_dev *pcdev) { - pcdev->syncpt_csi_a = + pcdev->syncpt_csi = nvhost_syncpt_read_ext(pcdev->ndev, - TEGRA_VI_SYNCPT_CSI_A); - - pcdev->syncpt_csi_b = - nvhost_syncpt_read_ext(pcdev->ndev, - TEGRA_VI_SYNCPT_CSI_B); + TEGRA_VI_SYNCPT_CSI); pcdev->syncpt_vi = nvhost_syncpt_read_ext(pcdev->ndev, @@ -394,65 +371,60 @@ static void tegra_camera_save_syncpts(struct tegra_camera_dev *pcdev) static void tegra_camera_incr_syncpts(struct tegra_camera_dev *pcdev) { nvhost_syncpt_cpu_incr_ext(pcdev->ndev, - TEGRA_VI_SYNCPT_CSI_A); - - nvhost_syncpt_cpu_incr_ext(pcdev->ndev, - TEGRA_VI_SYNCPT_CSI_B); + TEGRA_VI_SYNCPT_CSI); nvhost_syncpt_cpu_incr_ext(pcdev->ndev, TEGRA_VI_SYNCPT_VI); } -static void tegra_camera_capture_clean(struct tegra_camera_dev *pcdev) +static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev, + int input_format, + int yuv_input_format) { - TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000); - TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000); + struct soc_camera_device *icd = pcdev->icd; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_READONLY_STATUS, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_ESCAPE_MODE_DATA, 0x0); + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x02000000); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL, + (yuv_input_format << 8) | + (input_format << 2)); - TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_CONTROL, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_0, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_1, 0x0); - TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_2, 0x0); -} + TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000004); + TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000004); -static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev, - struct soc_camera_device *icd, - u32 hdr) -{ - struct tegra_camera_platform_data *pdata = icd->link->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); + /* CSI-A H_ACTIVE and V_ACTIVE */ + TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_H_ACTIVE, + (icd->user_width << 16)); + TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_V_ACTIVE, + (icd->user_height << 16)); + /* CSI A */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_A_CONTROL, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x00000000); - TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILA_CONTROL0, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_PAD_CONFIG0, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_PAD_CONFIG1, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x00000000); - TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME, 0x0); - - TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x02000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000); - /* CSI-A H_ACTIVE and V_ACTIVE */ - TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_H_ACTIVE, - (icd->user_width << 16)); - TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_V_ACTIVE, - (icd->user_height << 16)); + /* pad1s enabled, virtual channel ID 00 */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, + (0x1 << 16) | /* Output 1 pixel per clock */ + (0x1e << 8) | /* If hdr shows wrong fmt, use YUV422 */ + (0x1 << 7) | /* Check header CRC */ + (0x1 << 6) | /* Use word count field in the header */ + (0x1 << 5) | /* Look at data identifier byte in hdr */ + (0x1 << 4)); /* Expect packet header */ TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x1); /* Frame # for top field detect for interlaced */ @@ -466,27 +438,22 @@ static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev, (0x100 << 4) | /* Wait 0x100 vi clks for timeout */ 0x1); /* Enable line timeout */ - /* pad 0s enabled, virtual channel ID 00 */ - TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, - (0x1 << 16) | /* Output 1 pixel per clock */ - (hdr << 8) | /* If hdr shows wrong fmt, use right value */ - (0x1 << 7) | /* Check header CRC */ - (0x1 << 6) | /* Use word count field in the header */ - (0x1 << 5) | /* Look at data identifier byte in hdr */ - (0x1 << 4)); /* Expect packet header */ - TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_A_CONTROL, (0x3f << 16) | /* Skip packet threshold */ - (pdata->lanes - 1)); + (pcdev->pdata->lanes - 1)); /* Use 0x00000022 for continuous clock mode. */ TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILA_CONTROL0, - (pdata->continuous_clk << 5) | + (pcdev->pdata->continuous_clk << 5) | 0x5); /* Clock settle time */ TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END, (0x1 << 8) | /* Enable continuous syncpt */ - TEGRA_VI_SYNCPT_CSI_A); + TEGRA_VI_SYNCPT_CSI); + + TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1, + (0x1 << 8) | /* Enable continuous syncpt */ + TEGRA_VI_SYNCPT_VI); TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CIL_COMMAND, 0x00020001); @@ -494,37 +461,49 @@ static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev, } static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev, - struct soc_camera_device *icd, - u32 hdr) + int input_format, + int yuv_input_format) { - struct tegra_camera_platform_data *pdata = icd->link->priv; + struct soc_camera_device *icd = pcdev->icd; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x04000000); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL, + (yuv_input_format << 8) | + (input_format << 2)); + + TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000008); + TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000008); + + /* CSI-B H_ACTIVE and V_ACTIVE */ + TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_H_ACTIVE, + (icd->user_width << 16)); + TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_V_ACTIVE, + (icd->user_height << 16)); + + /* CSI B */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x00000000); - TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILB_CONTROL0, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_PAD_CONFIG0, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_PAD_CONFIG1, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x00000000); - TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME, 0x0); - - TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x04000000); - - /* CSI-B H_ACTIVE and V_ACTIVE */ - TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_H_ACTIVE, - (icd->user_width << 16)); - TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_V_ACTIVE, - (icd->user_height << 16)); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000); + TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000); - /* pad 0s enabled, virtual channel ID 00 */ + /* pad1s enabled, virtual channel ID 00 */ TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, (0x1 << 16) | /* Output 1 pixel per clock */ - (hdr << 8) | /* If hdr shows wrong fmt, use right value */ + (0x1e << 8) | /* If hdr shows wrong fmt, use YUV422 */ (0x1 << 7) | /* Check header CRC */ (0x1 << 6) | /* Use word count field in the header */ (0x1 << 5) | /* Look at data identifier byte in hdr */ @@ -545,16 +524,20 @@ static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev, TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL, (0x3f << 16) | /* Skip packet threshold */ - (pdata->lanes - 1)); + (pcdev->pdata->lanes - 1)); /* Use 0x00000022 for continuous clock mode. */ TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILB_CONTROL0, - (pdata->continuous_clk << 5) | + (pcdev->pdata->continuous_clk << 5) | 0x5); /* Clock settle time */ TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END, (0x1 << 8) | /* Enable continuous syncpt */ - TEGRA_VI_SYNCPT_CSI_B); + TEGRA_VI_SYNCPT_CSI); + + TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1, + (0x1 << 8) | /* Enable continuous syncpt */ + TEGRA_VI_SYNCPT_VI); TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CIL_COMMAND, 0x00010002); @@ -562,17 +545,22 @@ static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev, } static void tegra_camera_capture_setup_vip(struct tegra_camera_dev *pcdev, - struct soc_camera_device *icd, - u32 input_control) + int input_format, + int yuv_input_format) { + struct soc_camera_device *icd = pcdev->icd; TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL, - (1 << 27) | /* field detect */ - (1 << 25) | /* hsync/vsync decoded from data (BT.656) */ +// (1 << 27) | /* field detect */ + (0 << 28) | /* 1 == top field is even field, 00 == odd */ + ((internal_sync == 1) << 25) | /* 1 == hsync/vsync decoded + internally from data + (BT.656) */ + (yuv_input_format << 8) | (1 << 1) | /* VIP_INPUT_ENABLE */ - input_control); + (input_format << 2)); TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000000); TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000000); @@ -580,180 +568,80 @@ static void tegra_camera_capture_setup_vip(struct tegra_camera_dev *pcdev, /* VIP H_ACTIVE and V_ACTIVE */ TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_H_ACTIVE, (icd->user_width << 16) | - TEGRA_VIP_H_ACTIVE_START); + (TEGRA_VIP_H_ACTIVE_START - ((internal_sync == 1)?1:0))); TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_V_ACTIVE, - (icd->user_height << 16) | + ( ( IS_INTERLACED ? (icd->user_height/2) : (icd->user_height) ) << 16) | TEGRA_VIP_V_ACTIVE_START); /* * For VIP, D9..D2 is mapped to the video decoder's P7..P0. * Disable/mask out the other Dn wires. */ - TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INPUT_ENABLE, 0x000003fc); + TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INPUT_ENABLE, 0x000003fc | 0x6000); // D2..D9 + VSYNC + HSYNC TC_VI_REG_WT(pcdev, TEGRA_VI_VI_DATA_INPUT_CONTROL, 0x000003fc); TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INVERSION, 0x00000000); - TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_VIP_VSYNC, + TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1, (0x1 << 8) | /* Enable continuous syncpt */ TEGRA_VI_SYNCPT_VI); - TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, 0x00000004); +// TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, 0x00000004); } -static int tegra_camera_capture_output_channel_setup( - struct tegra_camera_dev *pcdev, - struct soc_camera_device *icd) +static void tegra_camera_capture_setup(struct tegra_camera_dev *pcdev) { - struct tegra_camera_platform_data *pdata = icd->link->priv; - int port = pdata->port; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); + struct soc_camera_device *icd = pcdev->icd; const struct soc_camera_format_xlate *current_fmt = icd->current_fmt; + enum v4l2_mbus_pixelcode input_code = current_fmt->code; u32 output_fourcc = current_fmt->host_fmt->fourcc; - u32 output_format, output_control; - struct tegra_buffer *buf = to_tegra_vb(pcdev->active); + int yuv_input_format = 0x0; + int input_format = 0x0; /* Default to YUV422 */ + int yuv_output_format = 0x0; + int output_format = 0x3; /* Default to YUV422 */ + int port = pcdev->pdata->port; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + int frame_count = 1; + + switch (input_code) { + case V4L2_MBUS_FMT_UYVY8_2X8: + yuv_input_format = 0x2; + break; + case V4L2_MBUS_FMT_VYUY8_2X8: + yuv_input_format = 0x3; + break; + case V4L2_MBUS_FMT_YUYV8_2X8: + yuv_input_format = 0x0; + break; + case V4L2_MBUS_FMT_YVYU8_2X8: + yuv_input_format = 0x1; + break; + default: + BUG_ON(1); + } switch (output_fourcc) { case V4L2_PIX_FMT_UYVY: - output_format = 0x3; /* Default to YUV422 */ + yuv_output_format = 0x0; break; case V4L2_PIX_FMT_VYUY: - output_format = (0x1 << 17) | 0x3; + yuv_output_format = 0x1; break; case V4L2_PIX_FMT_YUYV: - output_format = (0x2 << 17) | 0x3; + yuv_output_format = 0x2; break; case V4L2_PIX_FMT_YVYU: - output_format = (0x3 << 17) | 0x3; + yuv_output_format = 0x3; break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: output_format = 0x6; /* YUV420 planar */ break; - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SBGGR10: - /* Use second output channel for RAW8/RAW10 */ - buf->output_channel = 1; - - if (port == TEGRA_CAMERA_PORT_CSI_A) - output_format = 0x7; - else if (port == TEGRA_CAMERA_PORT_CSI_B) - output_format = 0x8; - else - output_format = 0x9; - break; default: - dev_err(&pcdev->ndev->dev, "Wrong output format %d\n", - output_fourcc); - return -EINVAL; + BUG_ON(1); } - output_control = (pdata->flip_v ? (0x1 << 20) : 0) | - (pdata->flip_h ? (0x1 << 19) : 0) | - output_format; - - if (buf->output_channel == 0) { - TC_VI_REG_WT(pcdev, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL, - output_control); - /* - * Set up frame size. Bits 31:16 are the number of lines, and - * bits 15:0 are the number of pixels per line. - */ - TC_VI_REG_WT(pcdev, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE, - (icd->user_height << 16) | icd->user_width); - - /* First output memory enabled */ - TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000); - - /* Set the number of frames in the buffer. */ - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_FIRST, 0x00000001); - - /* Set up buffer frame size. */ - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_FIRST, - (icd->user_height << 16) | icd->user_width); - - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST, - (icd->user_height * bytes_per_line)); - - TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1, - (0x1 << 8) | /* Enable continuous syncpt */ - TEGRA_VI_SYNCPT_VI); - - TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000); - } else if (buf->output_channel == 1) { - TC_VI_REG_WT(pcdev, TEGRA_VI_VI_SECOND_OUTPUT_CONTROL, - output_control); - - TC_VI_REG_WT(pcdev, TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE, - (icd->user_height << 16) | icd->user_width); - - TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE_2, 0x00000000); - - /* Set the number of frames in the buffer. */ - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_SECOND, 0x00000001); - - /* Set up buffer frame size. */ - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_SECOND, - (icd->user_height << 16) | icd->user_width); - - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_SECOND, - (icd->user_height * bytes_per_line)); - - TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_2, - (0x1 << 8) | /* Enable continuous syncpt */ - TEGRA_VI_SYNCPT_VI); - - TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE_2, 0x00000000); - } else { - dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n", - buf->output_channel); - return -EINVAL; - } - - return 0; -} - -static int tegra_camera_capture_setup(struct tegra_camera_dev *pcdev) -{ - struct vb2_buffer *vb = pcdev->active; - struct tegra_buffer *buf = to_tegra_vb(vb); - struct soc_camera_device *icd = buf->icd; - struct tegra_camera_platform_data *pdata = icd->link->priv; - int port = pdata->port; - const struct soc_camera_format_xlate *current_fmt = icd->current_fmt; - enum v4l2_mbus_pixelcode input_code = current_fmt->code; - u32 hdr, input_control = 0x0; - - switch (input_code) { - case V4L2_MBUS_FMT_UYVY8_2X8: - input_control |= 0x2 << 8; - hdr = 30; - break; - case V4L2_MBUS_FMT_VYUY8_2X8: - input_control |= 0x3 << 8; - hdr = 30; - break; - case V4L2_MBUS_FMT_YUYV8_2X8: - input_control |= 0x0; - hdr = 30; - break; - case V4L2_MBUS_FMT_YVYU8_2X8: - input_control |= 0x1 << 8; - hdr = 30; - break; - case V4L2_MBUS_FMT_SBGGR8_1X8: - input_control |= 0x2 << 2; /* Input Format = Bayer */ - hdr = 42; - break; - case V4L2_MBUS_FMT_SBGGR10_1X10: - input_control |= 0x2 << 2; /* Input Format = Bayer */ - hdr = 43; - break; - default: - dev_err(&pcdev->ndev->dev, "Input format %d is not supported\n", - input_code); - return -EINVAL; - } + BUG_ON(!tegra_camera_port_is_valid(port)); /* * Set up low pass filter. Use 0x240 for chromaticity and 0x240 @@ -765,25 +653,98 @@ static int tegra_camera_capture_setup(struct tegra_camera_dev *pcdev) /* Set up raise-on-edge, so we get an interrupt on end of frame. */ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_RAISE, 0x00000001); - /* Cleanup registers */ - tegra_camera_capture_clean(pcdev); - - /* Setup registers for CSI-A, CSI-B and VIP inputs */ if (port == TEGRA_CAMERA_PORT_CSI_A) - tegra_camera_capture_setup_csi_a(pcdev, icd, hdr); + tegra_camera_capture_setup_csi_a(pcdev, input_format, + yuv_input_format); else if (port == TEGRA_CAMERA_PORT_CSI_B) - tegra_camera_capture_setup_csi_b(pcdev, icd, hdr); + tegra_camera_capture_setup_csi_b(pcdev, input_format, + yuv_input_format); else - tegra_camera_capture_setup_vip(pcdev, icd, input_control); + tegra_camera_capture_setup_vip(pcdev, input_format, + yuv_input_format); + + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL, + (pcdev->pdata->flip_v ? (0x1 << 20) : 0) | + (pcdev->pdata->flip_h ? (0x1 << 19) : 0) | + (yuv_output_format << 17) | + output_format); + + // if the video is interlaced, then take two frames + frame_count = IS_INTERLACED ? 2 : 1; + + /* + * Set up frame size. Bits 31:16 are the number of lines, and + * bits 15:0 are the number of pixels per line. + */ + TC_VI_REG_WT(pcdev, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE, + ((icd->user_height/frame_count) << 16) | icd->user_width); + + /* Set the number of frames in the buffer. */ + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_FIRST, frame_count); + + /* Set up buffer frame size. */ + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_FIRST, + ((icd->user_height/frame_count) << 16) | icd->user_width); + if(output_fourcc == V4L2_PIX_FMT_YUV420 || output_fourcc == V4L2_PIX_FMT_YVU420) { + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST, + ((icd->user_height/frame_count) * icd->user_width) | (2<<30)); + } + else { + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST, + ((icd->user_height/frame_count) * bytes_per_line) | (2<<30)); + } + + /* First output memory enabled */ + TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000); - /* Setup registers for output channels */ - return tegra_camera_capture_output_channel_setup(pcdev, icd); } -static int tegra_camera_capture_buffer_setup(struct tegra_camera_dev *pcdev, - struct tegra_buffer *buf) +// +// make_interlaced +// +// make one interlaced frame out of two frames in the buffer @ addr +// this function must be issued for Y, U and V buffers. +// +static void make_interlaced(uint8_t * addr, int width, int height) { + uint8_t starting_line_buf[width]; + bool lines[height]; + int i; + int destination_line, starting_line; + for (i = 1; i < height-1; i++) lines[i] = false; + lines[0] = true; + lines[height-1] = true; + + #define real_line(i) ( (i % 2) ? ((i / 2) + (height/2)) : (i / 2) ) + while (1) { + starting_line = -1; + for (i = 1; i < ((height)-1); i++) if (!lines[i]) { + starting_line = i; + break; + } + if (starting_line == -1) break; // all is done + + memcpy(starting_line_buf, (void*) ((unsigned int)(addr) + (width*starting_line)), width); + destination_line = starting_line; + while (1) { + lines[destination_line] = true; + if (real_line(destination_line) == starting_line) { + memcpy(addr + width * destination_line, starting_line_buf, width); + break; + } + memcpy(addr + (width * destination_line), (void*) ((unsigned int)(addr) + (width * real_line(destination_line))), width); + destination_line = real_line(destination_line); + } + } +} + +static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev, + struct tegra_buffer *buf) { - struct soc_camera_device *icd = buf->icd; + struct soc_camera_device *icd = pcdev->icd; + int port = pcdev->pdata->port; + int err; + int bytes_per_line; + uint8_t *src; switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_YUV420: @@ -802,90 +763,87 @@ static int tegra_camera_capture_buffer_setup(struct tegra_camera_dev *pcdev, case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SBGGR10: - /* output 1 */ - if (buf->output_channel == 0) { - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_FIRST, - buf->buffer_addr); - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_FIRST, - buf->start_addr); - /* output 2 */ - } else if (buf->output_channel == 1) { - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_SECOND, - buf->buffer_addr); - TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_SECOND, - buf->start_addr); - } else { - dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n", - buf->output_channel); - return -EINVAL; - } - break; + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_FIRST, + buf->buffer_addr); + TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_FIRST, + buf->start_addr); + + break; default: - dev_err(&pcdev->ndev->dev, "Wrong host format %d\n", - icd->current_fmt->host_fmt->fourcc); - return -EINVAL; + BUG_ON(1); } - return 0; -} + BUG_ON(!tegra_camera_port_is_valid(port)); -static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev, - struct tegra_buffer *buf) -{ - struct soc_camera_device *icd = buf->icd; - struct tegra_camera_platform_data *pdata = icd->link->priv; - int port = pdata->port; - int err; + if (port == TEGRA_CAMERA_PORT_CSI_A) + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, + 0x0000f005); + else if (port == TEGRA_CAMERA_PORT_CSI_B) + TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, + 0x0000f005); + else + TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, + 0x00000005); // start & stop - err = tegra_camera_capture_buffer_setup(pcdev, buf); - if (err < 0) - return err; /* * Only wait on CSI frame end syncpt if we're using CSI. Otherwise, * wait on VIP VSYNC syncpt. */ - if (port == TEGRA_CAMERA_PORT_CSI_A) { - pcdev->syncpt_csi_a++; - TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, - 0x0000f005); - err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev, - TEGRA_VI_SYNCPT_CSI_A, - pcdev->syncpt_csi_a, - TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, - NULL); - } else if (port == TEGRA_CAMERA_PORT_CSI_B) { - pcdev->syncpt_csi_b++; - TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, - 0x0000f005); + + pcdev->syncpt_vi++; + pcdev->syncpt_csi++; + + if (tegra_camera_port_is_csi(port)) err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev, - TEGRA_VI_SYNCPT_CSI_B, - pcdev->syncpt_csi_b, - TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, - NULL); - } else { - pcdev->syncpt_vi++; - TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, - 0x00000001); + TEGRA_VI_SYNCPT_CSI, + pcdev->syncpt_csi, + TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, + NULL); + else err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev, - TEGRA_VI_SYNCPT_VI, - pcdev->syncpt_csi_a, - TEGRA_SYNCPT_VI_WAIT_TIMEOUT, - NULL); - } + TEGRA_VI_SYNCPT_VI, + pcdev->syncpt_vi, + TEGRA_SYNCPT_VI_WAIT_TIMEOUT, + NULL); - if (!err) - return 0; + if (IS_INTERLACED) { + + TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, + 0x00000005); // start & stop + + pcdev->syncpt_vi++; + pcdev->syncpt_csi++; + + err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev, + TEGRA_VI_SYNCPT_VI, + pcdev->syncpt_vi, + TEGRA_SYNCPT_VI_WAIT_TIMEOUT, + NULL); + + src = (uint8_t*)(buf->virtual_addr); + if(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YUV420 || icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YVU420 ) { + make_interlaced(src, icd->user_width, icd->user_height); // Y + make_interlaced(src + icd->user_width * icd->user_height, icd->user_width, icd->user_height/4); // U + make_interlaced(src + icd->user_width * icd->user_height + (icd->user_width * icd->user_height)/4, icd->user_width, icd->user_height/4); // V + } + else { + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + make_interlaced(src, bytes_per_line, icd->user_height); // Y + } + } + + if (!err) + return 0; if (tegra_camera_port_is_csi(port)) { u32 ppstatus; u32 cilstatus; u32 rostatus; - dev_warn(&icd->vdev->dev, "Timeout on CSI syncpt\n"); - dev_warn(&icd->vdev->dev, "buffer_addr = 0x%08x\n", + dev_err(&pcdev->ndev->dev, "Timeout on CSI syncpt\n"); + dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n", buf->buffer_addr); ppstatus = TC_VI_REG_RD(pcdev, @@ -895,7 +853,7 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev, rostatus = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_READONLY_STATUS); - dev_warn(&icd->vdev->dev, + dev_err(&pcdev->ndev->dev, "PPSTATUS = 0x%08x, " "CILSTATUS = 0x%08x, " "ROSTATUS = 0x%08x\n", @@ -903,14 +861,14 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev, } else { u32 vip_input_status; - dev_warn(&pcdev->ndev->dev, "Timeout on VI syncpt\n"); - dev_warn(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n", + dev_err(&pcdev->ndev->dev, "Timeout on VI syncpt\n"); + dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n", buf->buffer_addr); vip_input_status = TC_VI_REG_RD(pcdev, TEGRA_VI_VIP_INPUT_STATUS); - dev_warn(&pcdev->ndev->dev, + dev_err(&pcdev->ndev->dev, "VIP_INPUT_STATUS = 0x%08x\n", vip_input_status); } @@ -918,10 +876,12 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev, return err; } -static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port) +static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev) { + int port = pcdev->pdata->port; int err; - struct tegra_buffer *buf = to_tegra_vb(pcdev->active); + + BUG_ON(!tegra_camera_port_is_valid(port)); if (port == TEGRA_CAMERA_PORT_CSI_A) TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, @@ -929,9 +889,9 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port) else if (port == TEGRA_CAMERA_PORT_CSI_B) TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x0000f002); - else - TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, - 0x00000005); +// else +// TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, +// 0x00000005); if (tegra_camera_port_is_csi(port)) err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev, @@ -947,28 +907,17 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port) u32 ppstatus; u32 cilstatus; - dev_warn(&pcdev->ndev->dev, "Timeout on VI syncpt\n"); - - if (buf->output_channel == 0) - buffer_addr = TC_VI_REG_RD(pcdev, + dev_err(&pcdev->ndev->dev, "Timeout on VI syncpt\n"); + buffer_addr = TC_VI_REG_RD(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_FIRST); - else if (buf->output_channel == 1) - buffer_addr = TC_VI_REG_RD(pcdev, - TEGRA_VI_VB0_BASE_ADDRESS_SECOND); - else { - dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n", - buf->output_channel); - return -EINVAL; - } - - dev_warn(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n", + dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n", buffer_addr); ppstatus = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS); cilstatus = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS); - dev_warn(&pcdev->ndev->dev, + dev_err(&pcdev->ndev->dev, "PPSTATUS = 0x%08x, CILSTATUS = 0x%08x\n", ppstatus, cilstatus); } @@ -976,132 +925,81 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port) return err; } -static void tegra_camera_activate(struct tegra_camera_dev *pcdev) -{ - nvhost_module_busy_ext(pcdev->ndev); - - /* Enable external power */ - regulator_enable(pcdev->reg); - - /* Unpowergate VE */ - tegra_unpowergate_partition(TEGRA_POWERGATE_VENC); - - /* Turn on relevant clocks. */ - clk_set_rate(pcdev->clk_vi, 150000000); - clk_enable(pcdev->clk_vi); - clk_set_rate(pcdev->clk_vi_sensor, 24000000); - clk_enable(pcdev->clk_vi_sensor); - clk_enable(pcdev->clk_csi); - clk_enable(pcdev->clk_isp); - clk_enable(pcdev->clk_csus); - clk_set_rate(pcdev->clk_sclk, 80000000); - clk_enable(pcdev->clk_sclk); - clk_set_rate(pcdev->clk_sclk, 375000000); - clk_enable(pcdev->clk_emc); - - /* Save current syncpt values. */ - tegra_camera_save_syncpts(pcdev); -} - -static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev) -{ - /* Turn off relevant clocks. */ - clk_disable(pcdev->clk_vi); - clk_disable(pcdev->clk_vi_sensor); - clk_disable(pcdev->clk_csi); - clk_disable(pcdev->clk_isp); - clk_disable(pcdev->clk_csus); - clk_disable(pcdev->clk_sclk); - clk_disable(pcdev->clk_emc); - - /* Powergate VE */ - tegra_powergate_partition(TEGRA_POWERGATE_VENC); - - /* Disable external power */ - regulator_disable(pcdev->reg); - - nvhost_module_idle_ext(pcdev->ndev); - - pcdev->cal_done = 0; -} - static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev) { - struct vb2_buffer *vb = pcdev->active; - struct tegra_buffer *buf = to_tegra_vb(vb); - struct soc_camera_device *icd = buf->icd; - struct tegra_camera_platform_data *pdata = icd->link->priv; - int port = pdata->port; + struct vb2_buffer *vb; + struct tegra_buffer *buf; int retry = TEGRA_SYNCPT_RETRY_COUNT; - int err; + int port = pcdev->pdata->port; + int err = 0; - while (retry) { - err = tegra_camera_capture_start(pcdev, buf); - /* Capturing succeed, stop capturing */ - if (!err) - err = tegra_camera_capture_stop(pcdev, port); - /* Capturing failed, stop and retry */ - else { - retry--; - - /* Stop streaming. */ - if (port == TEGRA_CAMERA_PORT_CSI_A) { - TC_VI_REG_WT(pcdev, - TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, - 0x0000f002); - /* Clear status registers. */ - TC_VI_REG_WT(pcdev, - TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, - 0xffffffff); - TC_VI_REG_WT(pcdev, - TEGRA_CSI_CSI_CIL_STATUS, - 0xffffffff); - } else if (port == TEGRA_CAMERA_PORT_CSI_B) { - TC_VI_REG_WT(pcdev, - TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, - 0x0000f002); - /* Clear status registers. */ - TC_VI_REG_WT(pcdev, - TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, - 0xffffffff); - TC_VI_REG_WT(pcdev, - TEGRA_CSI_CSI_CIL_STATUS, - 0xffffffff); - } else { - TC_VI_REG_WT(pcdev, - TEGRA_VI_CAMERA_CONTROL, - 0x00000005); - } + if (!pcdev->active) + return 0; - tegra_camera_incr_syncpts(pcdev); - tegra_camera_save_syncpts(pcdev); + vb = pcdev->active; + buf = to_tegra_vb(vb); - continue; + while (retry--) { + err = tegra_camera_capture_start(pcdev, buf); + if (err == 0) { + err = tegra_camera_capture_stop(pcdev); + if (err == 0) break; } - break; - } + /* Stop streaming. */ + if (port == TEGRA_CAMERA_PORT_CSI_A) { + TC_VI_REG_WT(pcdev, + TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, + 0x0000f002); + /* Clear status registers. */ + TC_VI_REG_WT(pcdev, + TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, + 0xffffffff); + TC_VI_REG_WT(pcdev, + TEGRA_CSI_CSI_CIL_STATUS, + 0xffffffff); + } else if (port == TEGRA_CAMERA_PORT_CSI_B) { + TC_VI_REG_WT(pcdev, + TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, + 0x0000f002); + /* Clear status registers. */ + TC_VI_REG_WT(pcdev, + TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, + 0xffffffff); + TC_VI_REG_WT(pcdev, + TEGRA_CSI_CSI_CIL_STATUS, + 0xffffffff); + } else { + TC_VI_REG_WT(pcdev, + TEGRA_VI_CAMERA_CONTROL, + 0x00000005); + } - /* Reset hardware for too many errors */ - if (!retry) { - tegra_camera_deactivate(pcdev); - mdelay(5); - tegra_camera_activate(pcdev); - if (pcdev->active) - tegra_camera_capture_setup(pcdev); + tegra_camera_incr_syncpts(pcdev); + tegra_camera_save_syncpts(pcdev); + continue; } spin_lock_irq(&pcdev->videobuf_queue_lock); + /* + * If vb->state is VB2_BUF_STATE_ERROR, then the vb has already been + * removed, so we shouldn't remove it again. + */ + if (vb->state != VB2_BUF_STATE_ERROR) + list_del_init(&buf->queue); + + if (!list_empty(&pcdev->capture)) + pcdev->active = &list_entry(pcdev->capture.next, + struct tegra_buffer, queue)->vb; + else + pcdev->active = NULL; + do_gettimeofday(&vb->v4l2_buf.timestamp); vb->v4l2_buf.field = pcdev->field; - if (port == TEGRA_CAMERA_PORT_CSI_A) - vb->v4l2_buf.sequence = pcdev->sequence_a++; - else if (port == TEGRA_CAMERA_PORT_CSI_B) - vb->v4l2_buf.sequence = pcdev->sequence_b++; + vb->v4l2_buf.sequence = pcdev->sequence++; - vb2_buffer_done(vb, err < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - list_del_init(&buf->queue); + vb2_buffer_done(vb, (err != 0) ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); pcdev->num_frames++; @@ -1110,145 +1008,101 @@ static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev) return err; } -static int tegra_camera_csi_pad_calibration(struct tegra_camera_dev *pcdev) +static void tegra_camera_work(struct work_struct *work) { - struct vb2_buffer *vb = pcdev->active; - struct tegra_buffer *buf = to_tegra_vb(vb); - struct soc_camera_device *icd = buf->icd; - struct tegra_camera_platform_data *pdata = icd->link->priv; - int port = pdata->port; - int retry = 500; - u32 data; - int err = -EINVAL; - - TC_VI_REG_WT(pcdev, TEGRA_CSI_DSI_MIPI_CAL_CONFIG, 0x40300); - TC_VI_REG_WT(pcdev, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0, 0x50700); - - if (port == TEGRA_CAMERA_PORT_CSI_B || pdata->lanes == 4) - TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x200004); - - data = 0x2a000004; - if (port == TEGRA_CAMERA_PORT_CSI_A) - data |= 0x200000; /* MIPI_CAL_SELA */ - TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, data); - - /* Start calibration */ - data |= 0x80000000; - TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, data); + struct tegra_camera_dev *pcdev = + container_of(work, struct tegra_camera_dev, work); - while (retry--) { - data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS); - if ((data & 0x8000) == 0x8000) - break; - udelay(20); - } - if (!retry) { - dev_warn(&pcdev->ndev->dev, "MIPI calibration timeout!\n"); - goto cal_out; - } + mutex_lock(&pcdev->work_mutex); - /* Clear status */ - TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, data); - retry = 500; - while (retry--) { - data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS); - if ((data & 0x8000) == 0x0) - break; - udelay(20); - } + while (pcdev->active) + tegra_camera_capture_frame(pcdev); - if (!retry) { - dev_warn(&pcdev->ndev->dev, - "Clear MIPI calibration status timeout!\n"); - goto cal_out; - } + mutex_unlock(&pcdev->work_mutex); +} - data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS); - err = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS); - if (data | err) { - dev_warn(&pcdev->ndev->dev, - "Calibration status not be cleared!\n"); - err = -EINVAL; - goto cal_out; - } +static void tegra_camera_activate(struct tegra_camera_dev *pcdev) +{ +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + u32 val; + void __iomem *apb_misc; +#endif - /* Calibration succeed */ - err = 0; + nvhost_module_busy_ext(pcdev->ndev); -cal_out: - TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, data); +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + if(!tegra_powergate_is_powered(TEGRA_POWERGATE_VENC)) + tegra_unpowergate_partition(TEGRA_POWERGATE_VENC); +#endif - /* un-select to avoid interference with DSI */ - if (port == TEGRA_CAMERA_PORT_CSI_B || pdata->lanes == 4) - TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x4); + /* Turn on relevant clocks. */ + clk_enable(pcdev->clk_vi); + clk_enable(pcdev->clk_vi_sensor); + clk_enable(pcdev->clk_csi); + clk_enable(pcdev->clk_isp); + clk_enable(pcdev->clk_csus); - TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x2a000004); +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE); + val = readl(apb_misc + 0x42c); + writel(val | 0x1, apb_misc + 0x42c); +#endif - return err; + /* Save current syncpt values. */ + tegra_camera_save_syncpts(pcdev); } -static void tegra_camera_work(struct work_struct *work) +static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev) { - struct tegra_camera_dev *pcdev = - container_of(work, struct tegra_camera_dev, work); - struct tegra_buffer *buf; + mutex_lock(&pcdev->work_mutex); - while (1) { - mutex_lock(&pcdev->work_mutex); - - spin_lock_irq(&pcdev->videobuf_queue_lock); - if (list_empty(&pcdev->capture)) { - pcdev->active = NULL; - spin_unlock_irq(&pcdev->videobuf_queue_lock); - mutex_unlock(&pcdev->work_mutex); - return; - } + /* Cancel active buffer. */ + if (pcdev->active) { + list_del_init(&to_tegra_vb(pcdev->active)->queue); + vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR); + pcdev->active = NULL; + } - buf = list_entry(pcdev->capture.next, struct tegra_buffer, - queue); - pcdev->active = &buf->vb; - spin_unlock_irq(&pcdev->videobuf_queue_lock); + mutex_unlock(&pcdev->work_mutex); - tegra_camera_capture_setup(pcdev); - if (!pcdev->cal_done) { - tegra_camera_csi_pad_calibration(pcdev); - pcdev->cal_done = 1; - } - tegra_camera_capture_frame(pcdev); + /* Turn off relevant clocks. */ + clk_disable(pcdev->clk_vi); + clk_disable(pcdev->clk_vi_sensor); + clk_disable(pcdev->clk_csi); + clk_disable(pcdev->clk_isp); + clk_disable(pcdev->clk_csus); + + nvhost_module_idle_ext(pcdev->ndev); - mutex_unlock(&pcdev->work_mutex); - } } -static int tegra_camera_init_buffer(struct tegra_buffer *buf) +static void tegra_camera_init_buffer(struct tegra_camera_dev *pcdev, + struct tegra_buffer *buf) { - struct soc_camera_device *icd = buf->icd; + struct soc_camera_device *icd = pcdev->icd; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - struct tegra_camera_platform_data *pdata = icd->link->priv; + buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0); // physical addr + buf->virtual_addr = vb2_plane_vaddr(&buf->vb, 0); // save virtual addr for later interlace handling switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SBGGR10: - buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0); buf->start_addr = buf->buffer_addr; - if (pdata->flip_v) + if (pcdev->pdata->flip_v) buf->start_addr += bytes_per_line * (icd->user_height-1); - if (pdata->flip_h) + if (pcdev->pdata->flip_h) buf->start_addr += bytes_per_line - 1; break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0); buf->buffer_addr_u = buf->buffer_addr + icd->user_width * icd->user_height; buf->buffer_addr_v = buf->buffer_addr_u + @@ -1265,7 +1119,7 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf) buf->start_addr_u = buf->buffer_addr_u; buf->start_addr_v = buf->buffer_addr_v; - if (pdata->flip_v) { + if (pcdev->pdata->flip_v) { buf->start_addr += icd->user_width * (icd->user_height - 1); @@ -1276,7 +1130,7 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf) ((icd->user_height/2) - 1)); } - if (pdata->flip_h) { + if (pcdev->pdata->flip_h) { buf->start_addr += icd->user_width - 1; buf->start_addr_u += (icd->user_width/2) - 1; @@ -1287,12 +1141,8 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf) break; default: - dev_err(icd->parent, "Wrong host format %d\n", - icd->current_fmt->host_fmt->fourcc); - return -EINVAL; + BUG_ON(1); } - - return 0; } /* @@ -1307,7 +1157,6 @@ static int tegra_camera_videobuf_setup(struct vb2_queue *vq, struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); - struct tegra_camera_platform_data *pdata = icd->link->priv; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct tegra_camera_dev *pcdev = ici->priv; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, @@ -1320,16 +1169,20 @@ static int tegra_camera_videobuf_setup(struct vb2_queue *vq, *num_planes = 1; - if (pdata->port == TEGRA_CAMERA_PORT_CSI_A) - pcdev->sequence_a = 0; - else if (pdata->port == TEGRA_CAMERA_PORT_CSI_B) - pcdev->sequence_b = 0; + pcdev->sequence = 0; sizes[0] = bytes_per_line * icd->user_height; alloc_ctxs[0] = pcdev->alloc_ctx; if (!*num_buffers) *num_buffers = 2; + dev_dbg(icd->parent, "num_buffers=%u, size=%lu\n", + *num_buffers, sizes[0]); + + tegra_camera_capture_setup(pcdev); + + dev_dbg(icd->parent, "Finished tegra_camera_videobuf_setup()\n"); + return 0; } @@ -1338,8 +1191,9 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb) struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct tegra_buffer *buf = to_tegra_vb(vb); - struct tegra_camera_platform_data *pdata = icd->link->priv; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct tegra_camera_dev *pcdev = ici->priv; + struct tegra_buffer *buf; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); unsigned long size; @@ -1349,19 +1203,7 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb) if (bytes_per_line < 0) return bytes_per_line; - buf->icd = icd; - - if (!pdata) { - dev_err(icd->parent, "No platform data for this device!\n"); - return -EINVAL; - } - - if (!tegra_camera_port_is_valid(pdata->port)) { - dev_err(icd->parent, - "Invalid camera port %d in platform data\n", - pdata->port); - return -EINVAL; - } + buf = to_tegra_vb(vb); dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, vb2_plane_vaddr(vb, 0), vb2_plane_size(vb, 0)); @@ -1375,10 +1217,7 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb) memset(vb2_plane_vaddr(vb, 0), 0xbd, vb2_plane_size(vb, 0)); #endif - if (!icd->current_fmt) { - dev_err(icd->parent, "%s NULL format point\n", __func__); - return -EINVAL; - } + BUG_ON(NULL == icd->current_fmt); size = icd->user_height * bytes_per_line; @@ -1390,7 +1229,11 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb) vb2_set_plane_payload(vb, 0, size); - return tegra_camera_init_buffer(buf); + tegra_camera_init_buffer(pcdev, buf); + + dev_dbg(icd->parent, "Finished tegra_camera_videobuf_prepare()\n"); + + return 0; } static void tegra_camera_videobuf_queue(struct vb2_buffer *vb) @@ -1402,12 +1245,18 @@ static void tegra_camera_videobuf_queue(struct vb2_buffer *vb) struct tegra_camera_dev *pcdev = ici->priv; struct tegra_buffer *buf = to_tegra_vb(vb); + dev_dbg(icd->parent, "In tegra_camera_videobuf_queue()\n"); + dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); spin_lock_irq(&pcdev->videobuf_queue_lock); list_add_tail(&buf->queue, &pcdev->capture); - schedule_work(&pcdev->work); + + if (!pcdev->active) { + pcdev->active = vb; + schedule_work(&pcdev->work); + } spin_unlock_irq(&pcdev->videobuf_queue_lock); dev_dbg(icd->parent, "Finished tegra_camera_videobuf_queue()\n"); @@ -1462,24 +1311,16 @@ static int tegra_camera_stop_streaming(struct vb2_queue *q) struct tegra_camera_dev *pcdev = ici->priv; struct list_head *buf_head, *tmp; - mutex_lock(&pcdev->work_mutex); spin_lock_irq(&pcdev->videobuf_queue_lock); - list_for_each_safe(buf_head, tmp, &pcdev->capture) { - struct tegra_buffer *buf = container_of(buf_head, - struct tegra_buffer, - queue); - if (buf->icd == icd) - list_del_init(buf_head); - } - spin_unlock_irq(&pcdev->videobuf_queue_lock); - if (pcdev->active) { - struct tegra_buffer *buf = to_tegra_vb(pcdev->active); - if (buf->icd == icd) - pcdev->active = NULL; - } + pcdev->active = NULL; + + list_for_each_safe(buf_head, tmp, &pcdev->capture) + list_del_init(buf_head); + + spin_unlock_irq(&pcdev->videobuf_queue_lock); mutex_unlock(&pcdev->work_mutex); @@ -1524,13 +1365,24 @@ static int tegra_camera_add_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct tegra_camera_dev *pcdev = ici->priv; + int err; - if (!pcdev->enable_refcnt) { - pm_runtime_get_sync(ici->v4l2_dev.dev); - tegra_camera_activate(pcdev); - pcdev->num_frames = 0; + if (pcdev->icd) + return -EBUSY; + + pm_runtime_get_sync(ici->v4l2_dev.dev); + + if (pcdev->pdata->enable_camera) { + err = pcdev->pdata->enable_camera(pcdev->ndev); + if (IS_ERR_VALUE(err)) + return err; } - pcdev->enable_refcnt++; + + tegra_camera_activate(pcdev); + + pcdev->icd = icd; + + pcdev->num_frames = 0; dev_dbg(icd->parent, "TEGRA Camera host attached to camera %d\n", icd->devnum); @@ -1544,12 +1396,14 @@ static void tegra_camera_remove_device(struct soc_camera_device *icd) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct tegra_camera_dev *pcdev = ici->priv; - pcdev->enable_refcnt--; - if (!pcdev->enable_refcnt) { - cancel_work_sync(&pcdev->work); - tegra_camera_deactivate(pcdev); - pm_runtime_put_sync(ici->v4l2_dev.dev); - } + tegra_camera_deactivate(pcdev); + + pcdev->icd = NULL; + + if (pcdev->pdata->disable_camera) + pcdev->pdata->disable_camera(pcdev->ndev); + + pm_runtime_put_sync(ici->v4l2_dev.dev); dev_dbg(icd->parent, "Frames captured: %d\n", pcdev->num_frames); @@ -1591,8 +1445,6 @@ static int tegra_camera_get_formats(struct soc_camera_device *icd, case V4L2_MBUS_FMT_VYUY8_2X8: case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_YVYU8_2X8: - case V4L2_MBUS_FMT_SBGGR8_1X8: - case V4L2_MBUS_FMT_SBGGR10_1X10: formats += ARRAY_SIZE(tegra_camera_formats); for (k = 0; xlate && (k < ARRAY_SIZE(tegra_camera_formats)); @@ -1721,6 +1573,15 @@ static int tegra_camera_try_fmt(struct soc_camera_device *icd, case V4L2_FIELD_NONE: pix->field = V4L2_FIELD_NONE; break; + case V4L2_FIELD_INTERLACED_BT: + pix->field = V4L2_FIELD_INTERLACED_BT; + break; + case V4L2_FIELD_INTERLACED_TB: + pix->field = V4L2_FIELD_INTERLACED_TB; + break; + case V4L2_FIELD_INTERLACED: + pix->field = V4L2_FIELD_INTERLACED; + break; default: /* TODO: support interlaced at least in pass-through mode */ dev_err(icd->parent, "Field type %d unsupported.\n", @@ -1785,7 +1646,8 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev, goto exit; } - pcdev->ndev = ndev; + pcdev->pdata = ndev->dev.platform_data; + pcdev->ndev = ndev; pcdev->ici.priv = pcdev; pcdev->ici.v4l2_dev.dev = &ndev->dev; @@ -1798,6 +1660,14 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev, spin_lock_init(&pcdev->videobuf_queue_lock); mutex_init(&pcdev->work_mutex); + nvhost_set_drvdata(ndev, pcdev); + + if (!tegra_camera_port_is_valid(pcdev->pdata->port)) { + dev_err(&ndev->dev, "Invalid camera port %d in platform data\n", + pcdev->pdata->port); + goto exit_free_pcdev; + } + pcdev->clk_vi = clk_get_sys("tegra_camera", "vi"); if (IS_ERR_OR_NULL(pcdev->clk_vi)) { dev_err(&ndev->dev, "Failed to get vi clock.\n"); @@ -1827,48 +1697,16 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev, dev_err(&ndev->dev, "Failed to get csus clock.\n"); goto exit_put_clk_isp; } - - pcdev->clk_sclk = clk_get_sys("tegra_camera", "sclk"); - if (IS_ERR_OR_NULL(pcdev->clk_sclk)) { - dev_err(&ndev->dev, "Failed to get sclk clock.\n"); - goto exit_put_clk_csus; - } - - pcdev->clk_emc = clk_get_sys("tegra_camera", "emc"); - if (IS_ERR_OR_NULL(pcdev->clk_emc)) { - dev_err(&ndev->dev, "Failed to get emc clock.\n"); - goto exit_put_clk_sclk; - } - clk_set_rate(pcdev->clk_vi, 150000000); clk_set_rate(pcdev->clk_vi_sensor, 24000000); - /* Get regulator pointer */ -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - pcdev->reg = regulator_get(&ndev->dev, "vcsi"); -#else - pcdev->reg = regulator_get(&ndev->dev, "avdd_dsi_csi"); -#endif - if (IS_ERR_OR_NULL(pcdev->reg)) { - dev_err(&ndev->dev, "%s: couldn't get regulator\n", - __func__); - goto exit_put_clk_emc; - } - - nvhost_set_drvdata(ndev, pcdev); err = nvhost_client_device_get_resources(ndev); - if (err) { - dev_err(&ndev->dev, "%s: nvhost get resources failed %d\n", - __func__, err); - goto exit_put_regulator; - } + if (err) + goto exit_put_clk_csus; - err = nvhost_client_device_init(ndev); - if (err) { - dev_err(&ndev->dev, "%s: nvhost init failed %d\n", - __func__, err); - goto exit_put_regulator; - } + // initialize nvhost client device only the first time + if (ndev->power_attrib == NULL) + nvhost_client_device_init(ndev); pcdev->vi_base = ndev->aperture; @@ -1876,10 +1714,10 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev, pm_runtime_enable(&ndev->dev); pm_runtime_resume(&ndev->dev); - pcdev->alloc_ctx = vb2_dma_nvmap_init_ctx(&ndev->dev); + pcdev->alloc_ctx = vb2_dma_nvmap_init_ctx(pcdev->ici.v4l2_dev.dev); if (IS_ERR(pcdev->alloc_ctx)) { err = PTR_ERR(pcdev->alloc_ctx); - goto exit_pm_disable; + goto exit_put_resources; } err = soc_camera_host_register(&pcdev->ici); @@ -1892,15 +1730,9 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev, exit_cleanup_alloc_ctx: vb2_dma_nvmap_cleanup_ctx(pcdev->alloc_ctx); -exit_pm_disable: +exit_put_resources: pm_runtime_disable(&ndev->dev); nvhost_client_device_put_resources(ndev); -exit_put_regulator: - regulator_put(pcdev->reg); -exit_put_clk_emc: - clk_put(pcdev->clk_emc); -exit_put_clk_sclk: - clk_put(pcdev->clk_sclk); exit_put_clk_csus: clk_put(pcdev->clk_csus); exit_put_clk_isp: @@ -1963,6 +1795,11 @@ static int tegra_camera_suspend(struct nvhost_device *ndev, pm_message_t state) /* Suspend the camera sensor. */ WARN_ON(!pcdev->icd->ops->suspend); pcdev->icd->ops->suspend(pcdev->icd, state); + + /* Power off the camera subsystem. */ + pcdev->pdata->disable_camera(pcdev->ndev); + + nvhost_module_idle_ext(nvhost_get_parent(ndev)); } return 0; @@ -1976,10 +1813,14 @@ static int tegra_camera_resume(struct nvhost_device *ndev) /* We only need to do something if a camera sensor is attached. */ if (pcdev->icd) { + nvhost_module_busy_ext(nvhost_get_parent(ndev)); + + /* Power on the camera subsystem. */ + pcdev->pdata->enable_camera(pcdev->ndev); + /* Resume the camera host. */ tegra_camera_save_syncpts(pcdev); - if (pcdev->active) - tegra_camera_capture_setup(pcdev); + tegra_camera_capture_setup(pcdev); /* Resume the camera sensor. */ WARN_ON(!pcdev->icd->ops->resume); @@ -2021,6 +1862,5 @@ module_exit(tegra_camera_exit); MODULE_DESCRIPTION("TEGRA SoC Camera Host driver"); MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>"); -MODULE_AUTHOR("Bryan Wu <pengw@nvidia.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("nvhost:" TEGRA_CAM_DRV_NAME); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 10dba0cbda97..1f131d797583 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -297,6 +297,7 @@ config MFD_STMPE GPIO: stmpe-gpio Keypad: stmpe-keypad Touchscreen: stmpe-ts + ADC: stmpe-adc config MFD_TC3589X bool "Support Toshiba TC35892 and variants" diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 2963689cf45c..0c556fa65dd2 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -350,6 +350,25 @@ static struct mfd_cell stmpe_ts_cell = { }; /* + * ADC (STMPE811) + */ + +static struct resource stmpe_adc_resources[] = { + { + .name = "STMPE_ADC", + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell stmpe_adc_cell = { + .name = "stmpe-adc", + .resources = stmpe_adc_resources, + .num_resources = ARRAY_SIZE(stmpe_adc_resources), +}; + +/* * STMPE811 */ @@ -381,6 +400,11 @@ static struct stmpe_variant_block stmpe811_blocks[] = { .irq = STMPE811_IRQ_TOUCH_DET, .block = STMPE_BLOCK_TOUCHSCREEN, }, + { + .cell = &stmpe_adc_cell, + .irq = STMPE811_IRQ_ADC, + .block = STMPE_BLOCK_ADC, + }, }; static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks, diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 9a146c8bba92..1c140e5ace4f 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -96,6 +96,7 @@ struct tps6586x { struct mutex lock; struct device *dev; struct i2c_client *client; + enum tps6586x_type type; struct gpio_chip gpio; struct irq_chip irq_chip; @@ -255,6 +256,14 @@ out: } EXPORT_SYMBOL_GPL(tps6586x_update); +enum tps6586x_type tps6586x_gettype(struct device *dev) +{ + struct tps6586x *tps6586x = dev_get_drvdata(dev); + + return tps6586x->type; +} +EXPORT_SYMBOL_GPL(tps6586x_gettype); + static struct i2c_client *tps6586x_i2c_client = NULL; static void tps6586x_power_off(void) { @@ -517,17 +526,36 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, return -ENOTSUPP; } + tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL); + if (tps6586x == NULL) + return -ENOMEM; + ret = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC); if (ret < 0) { dev_err(&client->dev, "Chip ID read failed: %d\n", ret); - return -EIO; + ret = -EIO; + goto err_irq_init; + } + tps6586x->type = (enum tps6586x_type)ret; + switch (ret) { + case TPS658621A: + dev_info(&client->dev, "found TPS658621A, "); + break; + case TPS658621D: + dev_info(&client->dev, "found TPS658621D, "); + break; + case TPS658623: + dev_info(&client->dev, "found TPS658623, "); + break; + case TPS658643: + dev_info(&client->dev, "found TPS658643, "); + break; + default: + dev_info(&client->dev, "unknown TPS6586X found, "); + tps6586x->type = TPS6586X_ANY; } - dev_info(&client->dev, "VERSIONCRC is %02x\n", ret); - - tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL); - if (tps6586x == NULL) - return -ENOMEM; + printk("VERSIONCRC is %02x\n", ret); tps6586x->client = client; tps6586x->dev = &client->dev; diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 8ff35e4cbfe4..73b65ce3089e 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -942,7 +942,13 @@ static struct sdhci_pltfm_data sdhci_tegra_pdata = { SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_NO_CALC_MAX_DISCARD_TO | - SDHCI_QUIRK_BROKEN_CARD_DETECTION, + SDHCI_QUIRK_BROKEN_CARD_DETECTION | +#if defined(CONFIG_MACH_APALIS_T30) || defined(CONFIG_MACH_COLIBRI_T30) +/* Hack: SDR12, SDR25, SDR50, SDR104 and DDR50 all require 1.8V signalling which + our current T30 designs can't do. */ + SDHCI_QUIRK2_NO_1_8_V | +#endif + 0, .ops = &tegra_sdhci_ops, }; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3a440dcf0f24..da1547ffc9da 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -486,7 +486,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, if (offset) { if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); +/* Hack to avoid extensive warning messages from Redpine Signals LiteFi driver */ +#ifndef CONFIG_MACH_COLIBRI_T20 WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); +#endif memcpy(align, buffer, offset); sdhci_kunmap_atomic(buffer, &flags); } @@ -2658,9 +2661,13 @@ int sdhci_add_host(struct sdhci_host *host) mmc_card_is_removable(mmc) && !(host->ops->get_cd)) mmc->caps |= MMC_CAP_NEEDS_POLL; - /* UHS-I mode(s) supported by the host controller. */ - if (host->version >= SDHCI_SPEC_300) - mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; + if (host->quirks & SDHCI_QUIRK2_NO_1_8_V) + caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50); + else + /* UHS-I mode(s) supported by the host controller. */ + if (host->version >= SDHCI_SPEC_300) + mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; /* SDR104 supports also implies SDR50 support */ if (caps[1] & SDHCI_SUPPORT_SDR104) diff --git a/drivers/mtd/devices/tegra_nand.c b/drivers/mtd/devices/tegra_nand.c index 38baa40746c6..6034f0b2f239 100644 --- a/drivers/mtd/devices/tegra_nand.c +++ b/drivers/mtd/devices/tegra_nand.c @@ -434,6 +434,35 @@ static int nand_cmd_get_status(struct tegra_nand_info *info, uint32_t *status) return 0; } +static int tegra_nand_cmd_reset(struct tegra_nand_info *info, + uint32_t *chip_id) +{ + int err; + uint32_t status = 0; + +#ifdef TEGRA_NAND_DEBUG_PEDANTIC + BUG_ON(info->chip.curr_chip == -1); +#endif + + info->command_reg = (COMMAND_CLE | + (COMMAND_CE(info->chip.curr_chip))); + writel(NAND_CMD_RESET, CMD_REG1); + writel(0, CMD_REG2); + writel(0, ADDR_REG1); + writel(0, ADDR_REG2); + writel(0, CONFIG_REG); + + err = tegra_nand_go(info); + if (err != 0) + return err; + + err = nand_cmd_get_status(info, &status); + if (err != 0) + return err; + + return 0; +} + /* must be called with lock held */ static int check_block_isbad(struct mtd_info *mtd, loff_t offs) { @@ -1400,6 +1429,11 @@ static int tegra_nand_scan(struct mtd_info *mtd, int maxchips) writel(0, CONFIG_REG); select_chip(info, 0); + + err = tegra_nand_cmd_reset(info, &tmp); + if (err != 0) + goto out_error; + err = tegra_nand_cmd_readid(info, &tmp); if (err != 0) goto out_error; @@ -1458,7 +1492,7 @@ static int tegra_nand_scan(struct mtd_info *mtd, int maxchips) /* page_size */ tmp = dev_parms & 0x3; - mtd->writesize = 1024 << tmp; + mtd->writesize = mtd->writebufsize = 1024 << tmp; info->chip.column_mask = mtd->writesize - 1; if (mtd->writesize > 4096) { @@ -1481,6 +1515,11 @@ static int tegra_nand_scan(struct mtd_info *mtd, int maxchips) /* data block size (erase size) (w/o spare) */ tmp = (dev_parms >> 4) & 0x3; + /* work around wrong block size identified for our device + Note: ONFI would really be the way to go but has not been supported + in Linux prior to version 2.6.37. */ + if ((vendor_id == 0x2C) && (dev_id == 0x38)) + tmp += 1; mtd->erasesize = (64 * 1024) << tmp; info->chip.block_shift = ffs(mtd->erasesize) - 1; /* bus width of the nand chip 8/16 */ diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 00cf1b0d6053..a56bf52acf5e 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -104,6 +104,7 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16}, /* 8 Gigabit */ + {"NAND 1GiB 1,8V 8-bit", 0x38, 0, 1024, 0, LP_OPTIONS}, {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS}, {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS}, {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16}, diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 330140ee266d..535e4032da2b 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -593,6 +593,18 @@ static int mcp251x_do_set_bittiming(struct net_device *net) return 0; } +static int mcp251x_get_berr_counter(const struct net_device *dev, struct can_berr_counter *bec) +{ + struct mcp251x_priv *priv = netdev_priv(dev); + struct spi_device *spi = priv->spi; + uint8_t tec,rec; + + mcp251x_read_2regs(spi, TEC, &tec, &rec); + bec->txerr = tec; + bec->rxerr = rec; + return 0; +} + static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv, struct spi_device *spi) { @@ -997,6 +1009,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi) priv = netdev_priv(net); priv->can.bittiming_const = &mcp251x_bittiming_const; priv->can.do_set_mode = mcp251x_do_set_mode; + priv->can.do_get_berr_counter = mcp251x_get_berr_counter; priv->can.clock.freq = pdata->oscillator_frequency / 2; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY; diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index d9fadc489b32..c8428f25d914 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -38,12 +38,24 @@ MODULE_LICENSE("GPL v2"); static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg) { +#if !defined(CONFIG_MACH_COLIBRI_T20) && !defined(CONFIG_MACH_COLIBRI_T30) return ioread8(priv->reg_base + reg); +#else + u8 value; + iowrite8(reg, priv->reg_base); + value = ioread8(priv->reg_base + 8); + return value; +#endif } static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val) { +#if !defined(CONFIG_MACH_COLIBRI_T20) && !defined(CONFIG_MACH_COLIBRI_T30) iowrite8(val, priv->reg_base + reg); +#else + iowrite8(reg, priv->reg_base); + iowrite8(val, priv->reg_base + 8); +#endif } static u8 sp_read_reg16(const struct sja1000_priv *priv, int reg) diff --git a/drivers/net/igb/Makefile b/drivers/net/igb/Makefile index c6e4621b6262..01193b8460fc 100644 --- a/drivers/net/igb/Makefile +++ b/drivers/net/igb/Makefile @@ -33,5 +33,6 @@ obj-$(CONFIG_IGB) += igb.o igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \ - e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o + e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \ + e1000_i210.o diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index c0857bdfb03a..ad3bf1792d7c 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -34,6 +34,7 @@ #include "e1000_mac.h" #include "e1000_82575.h" +#include "e1000_i210.h" static s32 igb_get_invariants_82575(struct e1000_hw *); static s32 igb_acquire_phy_82575(struct e1000_hw *); @@ -50,6 +51,8 @@ static s32 igb_write_phy_reg_82580(struct e1000_hw *, u32, u16); static s32 igb_reset_hw_82575(struct e1000_hw *); static s32 igb_reset_hw_82580(struct e1000_hw *); static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *, bool); +static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *, bool); +static s32 igb_set_d3_lplu_state_82580(struct e1000_hw *, bool); static s32 igb_setup_copper_link_82575(struct e1000_hw *); static s32 igb_setup_serdes_link_82575(struct e1000_hw *); static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16); @@ -98,6 +101,8 @@ static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw) break; case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: reg = rd32(E1000_MDICNFG); ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO); break; @@ -152,6 +157,17 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) case E1000_DEV_ID_I350_SGMII: mac->type = e1000_i350; break; + case E1000_DEV_ID_I210_COPPER: + case E1000_DEV_ID_I210_COPPER_OEM1: + case E1000_DEV_ID_I210_COPPER_IT: + case E1000_DEV_ID_I210_FIBER: + case E1000_DEV_ID_I210_SERDES: + case E1000_DEV_ID_I210_SGMII: + mac->type = e1000_i210; + break; + case E1000_DEV_ID_I211_COPPER: + mac->type = e1000_i211; + break; default: return -E1000_ERR_MAC_INIT; break; @@ -184,26 +200,44 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) /* Set mta register count */ mac->mta_reg_count = 128; /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES_82575; - if (mac->type == e1000_82576) + switch (mac->type) { + case e1000_82576: mac->rar_entry_count = E1000_RAR_ENTRIES_82576; - if (mac->type == e1000_82580) + break; + case e1000_82580: mac->rar_entry_count = E1000_RAR_ENTRIES_82580; - if (mac->type == e1000_i350) + break; + case e1000_i350: + case e1000_i210: + case e1000_i211: mac->rar_entry_count = E1000_RAR_ENTRIES_I350; + break; + default: + mac->rar_entry_count = E1000_RAR_ENTRIES_82575; + break; + } /* reset */ if (mac->type >= e1000_82580) mac->ops.reset_hw = igb_reset_hw_82580; else mac->ops.reset_hw = igb_reset_hw_82575; + + if (mac->type >= e1000_i210) { + mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_i210; + mac->ops.release_swfw_sync = igb_release_swfw_sync_i210; + } else { + mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_82575; + mac->ops.release_swfw_sync = igb_release_swfw_sync_82575; + } + /* Set if part includes ASF firmware */ mac->asf_firmware_present = true; /* Set if manageability features are enabled. */ mac->arc_subsystem_valid = (rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK) ? true : false; - /* enable EEE on i350 parts */ - if (mac->type == e1000_i350) + /* enable EEE on i350 parts and later parts */ + if (mac->type >= e1000_i350) dev_spec->eee_disable = false; else dev_spec->eee_disable = true; @@ -215,26 +249,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) /* NVM initialization */ eecd = rd32(E1000_EECD); - - nvm->opcode_bits = 8; - nvm->delay_usec = 1; - switch (nvm->override) { - case e1000_nvm_override_spi_large: - nvm->page_size = 32; - nvm->address_bits = 16; - break; - case e1000_nvm_override_spi_small: - nvm->page_size = 8; - nvm->address_bits = 8; - break; - default: - nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; - nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; - break; - } - - nvm->type = e1000_nvm_eeprom_spi; - size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> E1000_EECD_SIZE_EX_SHIFT); @@ -244,6 +258,33 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) */ size += NVM_WORD_SIZE_BASE_SHIFT; + nvm->word_size = 1 << size; + if (hw->mac.type < e1000_i210) { + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd + & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd + & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + if (nvm->word_size == (1 << 15)) + nvm->page_size = 128; + + nvm->type = e1000_nvm_eeprom_spi; + } else + nvm->type = e1000_nvm_flash_hw; + /* * Check for invalid size */ @@ -252,32 +293,60 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) "defaulting to 32K.\n"); size = 15; } - nvm->word_size = 1 << size; - if (nvm->word_size == (1 << 15)) - nvm->page_size = 128; /* NVM Function Pointers */ - nvm->ops.acquire = igb_acquire_nvm_82575; - if (nvm->word_size < (1 << 15)) - nvm->ops.read = igb_read_nvm_eerd; - else - nvm->ops.read = igb_read_nvm_spi; - - nvm->ops.release = igb_release_nvm_82575; switch (hw->mac.type) { case e1000_82580: nvm->ops.validate = igb_validate_nvm_checksum_82580; nvm->ops.update = igb_update_nvm_checksum_82580; + nvm->ops.acquire = igb_acquire_nvm_82575; + nvm->ops.release = igb_release_nvm_82575; + if (nvm->word_size < (1 << 15)) + nvm->ops.read = igb_read_nvm_eerd; + else + nvm->ops.read = igb_read_nvm_spi; + nvm->ops.write = igb_write_nvm_spi; break; case e1000_i350: nvm->ops.validate = igb_validate_nvm_checksum_i350; nvm->ops.update = igb_update_nvm_checksum_i350; + nvm->ops.acquire = igb_acquire_nvm_82575; + nvm->ops.release = igb_release_nvm_82575; + if (nvm->word_size < (1 << 15)) + nvm->ops.read = igb_read_nvm_eerd; + else + nvm->ops.read = igb_read_nvm_spi; + nvm->ops.write = igb_write_nvm_spi; + break; + case e1000_i210: + nvm->ops.validate = igb_validate_nvm_checksum_i210; + nvm->ops.update = igb_update_nvm_checksum_i210; + nvm->ops.acquire = igb_acquire_nvm_i210; + nvm->ops.release = igb_release_nvm_i210; + nvm->ops.read = igb_read_nvm_srrd_i210; + nvm->ops.valid_led_default = igb_valid_led_default_i210; + break; + case e1000_i211: + nvm->ops.acquire = igb_acquire_nvm_i210; + nvm->ops.release = igb_release_nvm_i210; + nvm->ops.read = igb_read_nvm_i211; + nvm->ops.valid_led_default = igb_valid_led_default_i210; + nvm->ops.validate = NULL; + nvm->ops.update = NULL; + nvm->ops.write = NULL; break; default: nvm->ops.validate = igb_validate_nvm_checksum; nvm->ops.update = igb_update_nvm_checksum; + nvm->ops.acquire = igb_acquire_nvm_82575; + nvm->ops.release = igb_release_nvm_82575; + if (nvm->word_size < (1 << 15)) + nvm->ops.read = igb_read_nvm_eerd; + else + nvm->ops.read = igb_read_nvm_spi; + nvm->ops.write = igb_write_nvm_spi; + break; } - nvm->ops.write = igb_write_nvm_spi; /* if part supports SR-IOV then initialize mailbox parameters */ switch (mac->type) { @@ -315,9 +384,13 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) { phy->ops.read_reg = igb_read_phy_reg_sgmii_82575; phy->ops.write_reg = igb_write_phy_reg_sgmii_82575; - } else if (hw->mac.type >= e1000_82580) { + } else if ((hw->mac.type == e1000_82580) + || (hw->mac.type == e1000_i350)) { phy->ops.read_reg = igb_read_phy_reg_82580; phy->ops.write_reg = igb_write_phy_reg_82580; + } else if (hw->phy.type >= e1000_phy_i210) { + phy->ops.read_reg = igb_read_phy_reg_gs40g; + phy->ops.write_reg = igb_write_phy_reg_gs40g; } else { phy->ops.read_reg = igb_read_phy_reg_igp; phy->ops.write_reg = igb_write_phy_reg_igp; @@ -346,6 +419,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) else phy->ops.get_cable_length = igb_get_cable_length_m88; + if (phy->id == I210_I_PHY_ID) { + phy->ops.get_cable_length = + igb_get_cable_length_m88_gen2; + phy->ops.set_d0_lplu_state = + igb_set_d0_lplu_state_82580; + phy->ops.set_d3_lplu_state = + igb_set_d3_lplu_state_82580; + } phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; break; case IGP03E1000_E_PHY_ID: @@ -362,6 +443,17 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580; phy->ops.get_cable_length = igb_get_cable_length_82580; phy->ops.get_phy_info = igb_get_phy_info_82580; + phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580; + phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580; + break; + case I210_I_PHY_ID: + phy->type = e1000_phy_i210; + phy->ops.get_phy_info = igb_get_phy_info_m88; + phy->ops.check_polarity = igb_check_polarity_m88; + phy->ops.get_cable_length = igb_get_cable_length_m88_gen2; + phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580; + phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580; + phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; break; default: return -E1000_ERR_PHY; @@ -388,7 +480,7 @@ static s32 igb_acquire_phy_82575(struct e1000_hw *hw) else if (hw->bus.func == E1000_FUNC_3) mask = E1000_SWFW_PHY3_SM; - return igb_acquire_swfw_sync_82575(hw, mask); + return hw->mac.ops.acquire_swfw_sync(hw, mask); } /** @@ -409,7 +501,7 @@ static void igb_release_phy_82575(struct e1000_hw *hw) else if (hw->bus.func == E1000_FUNC_3) mask = E1000_SWFW_PHY3_SM; - igb_release_swfw_sync_82575(hw, mask); + hw->mac.ops.release_swfw_sync(hw, mask); } /** @@ -513,6 +605,8 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw) break; case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: mdic = rd32(E1000_MDICNFG); mdic &= E1000_MDICNFG_PHY_MASK; phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT; @@ -677,6 +771,96 @@ out: } /** + * igb_set_d0_lplu_state_82580 - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: true to enable LPLU, false to disable + * + * Sets the LPLU D0 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 data; + + data = rd32(E1000_82580_PHY_POWER_MGMT); + + if (active) { + data |= E1000_82580_PM_D0_LPLU; + + /* When LPLU is enabled, we should disable SmartSpeed */ + data &= ~E1000_82580_PM_SPD; + } else { + data &= ~E1000_82580_PM_D0_LPLU; + + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) + data |= E1000_82580_PM_SPD; + else if (phy->smart_speed == e1000_smart_speed_off) + data &= ~E1000_82580_PM_SPD; } + + wr32(E1000_82580_PHY_POWER_MGMT, data); + return ret_val; +} + +/** + * igb_set_d3_lplu_state_82580 - Sets low power link up state for D3 + * @hw: pointer to the HW structure + * @active: boolean used to enable/disable lplu + * + * Success returns 0, Failure returns 1 + * + * The low power link up (lplu) state is set to the power management level D3 + * and SmartSpeed is disabled when active is true, else clear lplu for D3 + * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU + * is used during Dx states where the power conservation is most important. + * During driver activity, SmartSpeed should be enabled so performance is + * maintained. + **/ +s32 igb_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 data; + + data = rd32(E1000_82580_PHY_POWER_MGMT); + + if (!active) { + data &= ~E1000_82580_PM_D3_LPLU; + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) + data |= E1000_82580_PM_SPD; + else if (phy->smart_speed == e1000_smart_speed_off) + data &= ~E1000_82580_PM_SPD; + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + data |= E1000_82580_PM_D3_LPLU; + /* When LPLU is enabled, we should disable SmartSpeed */ + data &= ~E1000_82580_PM_SPD; + } + + wr32(E1000_82580_PHY_POWER_MGMT, data); + return ret_val; +} + +/** * igb_acquire_nvm_82575 - Request for access to EEPROM * @hw: pointer to the HW structure * @@ -689,14 +873,14 @@ static s32 igb_acquire_nvm_82575(struct e1000_hw *hw) { s32 ret_val; - ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + ret_val = hw->mac.ops.acquire_swfw_sync(hw, E1000_SWFW_EEP_SM); if (ret_val) goto out; ret_val = igb_acquire_nvm(hw); if (ret_val) - igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, E1000_SWFW_EEP_SM); out: return ret_val; @@ -712,7 +896,7 @@ out: static void igb_release_nvm_82575(struct e1000_hw *hw) { igb_release_nvm(hw); - igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, E1000_SWFW_EEP_SM); } /** @@ -1080,7 +1264,6 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw) * is no link. */ igb_clear_hw_cntrs_82575(hw); - return ret_val; } @@ -1117,6 +1300,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) } } switch (hw->phy.type) { + case e1000_phy_i210: case e1000_phy_m88: if (hw->phy.id == I347AT4_E_PHY_ID || hw->phy.id == M88E1112_E_PHY_ID) @@ -1740,7 +1924,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw) /* Determine whether or not a global dev reset is requested */ if (global_device_reset && - igb_acquire_swfw_sync_82575(hw, swmbsw_mask)) + hw->mac.ops.acquire_swfw_sync(hw, swmbsw_mask)) global_device_reset = false; if (global_device_reset && @@ -1786,7 +1970,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw) /* Release semaphore */ if (global_device_reset) - igb_release_swfw_sync_82575(hw, swmbsw_mask); + hw->mac.ops.release_swfw_sync(hw, swmbsw_mask); return ret_val; } diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index 786e110011a3..b477b20a2b05 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -55,10 +55,11 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); #define E1000_SRRCTL_DROP_EN 0x80000000 #define E1000_SRRCTL_TIMESTAMP 0x40000000 + #define E1000_MRQC_ENABLE_RSS_4Q 0x00000002 #define E1000_MRQC_ENABLE_VMDQ 0x00000003 -#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005 #define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 +#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005 #define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000 diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index 7b8ddd830f19..e32e3a71eff1 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -452,6 +452,7 @@ #define E1000_ERR_INVALID_ARGUMENT 16 #define E1000_ERR_NO_SPACE 17 #define E1000_ERR_NVM_PBA_SECTION 18 +#define E1000_ERR_INVM_VALUE_NOT_FOUND 19 /* Loop limit on how long we wait for auto-negotiation to complete */ #define COPPER_LINK_UP_LIMIT 10 @@ -589,6 +590,25 @@ #define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ #define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ #define E1000_EECD_SIZE_EX_SHIFT 11 +#define E1000_EECD_FLUPD_I210 0x00800000 /* Update FLASH */ +#define E1000_EECD_FLUDONE_I210 0x04000000 /* Update FLASH done*/ +#define E1000_FLUDONE_ATTEMPTS 20000 +#define E1000_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */ +#define E1000_I210_FIFO_SEL_RX 0x00 +#define E1000_I210_FIFO_SEL_TX_QAV(_i) (0x02 + (_i)) +#define E1000_I210_FIFO_SEL_TX_LEGACY E1000_I210_FIFO_SEL_TX_QAV(0) +#define E1000_I210_FIFO_SEL_BMC2OS_TX 0x06 +#define E1000_I210_FIFO_SEL_BMC2OS_RX 0x01 +#define E1000_EECD_FLUPD_I210 0x00800000 /* Update FLASH */ +#define E1000_EECD_FLUDONE_I210 0x04000000 /* Update FLASH done*/ +#define E1000_FLUDONE_ATTEMPTS 20000 +#define E1000_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */ +#define E1000_I210_FIFO_SEL_RX 0x00 +#define E1000_I210_FIFO_SEL_TX_QAV(_i) (0x02 + (_i)) +#define E1000_I210_FIFO_SEL_TX_LEGACY E1000_I210_FIFO_SEL_TX_QAV(0) +#define E1000_I210_FIFO_SEL_BMC2OS_TX 0x06 +#define E1000_I210_FIFO_SEL_BMC2OS_RX 0x01 + /* Offset to data in NVM read/write registers */ #define E1000_NVM_RW_REG_DATA 16 @@ -607,6 +627,16 @@ #define NVM_CHECKSUM_REG 0x003F #define NVM_COMPATIBILITY_REG_3 0x0003 #define NVM_COMPATIBILITY_BIT_MASK 0x8000 +#define NVM_MAC_ADDR 0x0000 +#define NVM_SUB_DEV_ID 0x000B +#define NVM_SUB_VEN_ID 0x000C +#define NVM_DEV_ID 0x000D +#define NVM_VEN_ID 0x000E +#define NVM_INIT_CTRL_2 0x000F +#define NVM_INIT_CTRL_4 0x0013 +#define NVM_LED_1_CFG 0x001C +#define NVM_LED_0_2_CFG 0x001F + #define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */ #define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */ @@ -633,6 +663,7 @@ #define NVM_PBA_OFFSET_0 8 #define NVM_PBA_OFFSET_1 9 +#define NVM_RESERVED_WORD 0xFFFF #define NVM_PBA_PTR_GUARD 0xFAFA #define NVM_WORD_SIZE_BASE_SHIFT 6 @@ -690,6 +721,7 @@ #define I82580_I_PHY_ID 0x015403A0 #define I350_I_PHY_ID 0x015403B0 #define M88_VENDOR 0x0141 +#define I210_I_PHY_ID 0x01410C00 /* M88E1000 Specific Registers */ #define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ @@ -809,6 +841,7 @@ #define E1000_IPCNFG_EEE_100M_AN 0x00000004 /* EEE Enable 100M AN */ #define E1000_EEER_TX_LPI_EN 0x00010000 /* EEE Tx LPI Enable */ #define E1000_EEER_RX_LPI_EN 0x00020000 /* EEE Rx LPI Enable */ +#define E1000_EEER_FRC_AN 0x10000000 /* Enable EEE in loopback */ #define E1000_EEER_LPI_FC 0x00040000 /* EEE Enable on FC */ /* SerDes Control */ diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 4519a1367170..6542df695834 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -63,6 +63,23 @@ struct e1000_hw; #define E1000_DEV_ID_I350_FIBER 0x1522 #define E1000_DEV_ID_I350_SERDES 0x1523 #define E1000_DEV_ID_I350_SGMII 0x1524 +#ifdef CONFIG_MACH_APALIS_T30 +/* Hack: Springville with a blank Flash (tools only, not for driver) */ +#define E1000_DEV_ID_I210_COPPER 0x1531 +#else +#define E1000_DEV_ID_I210_COPPER 0x1533 +#endif +#define E1000_DEV_ID_I210_COPPER_OEM1 0x1534 +#define E1000_DEV_ID_I210_COPPER_IT 0x1535 +#define E1000_DEV_ID_I210_FIBER 0x1536 +#define E1000_DEV_ID_I210_SERDES 0x1537 +#define E1000_DEV_ID_I210_SGMII 0x1538 +#ifdef CONFIG_MACH_APALIS_T30 +/* Hack: I211 with a blank iNVM (tools only, not for driver) */ +#define E1000_DEV_ID_I211_COPPER 0x1532 +#else +#define E1000_DEV_ID_I211_COPPER 0x1539 +#endif #define E1000_REVISION_2 2 #define E1000_REVISION_4 4 @@ -83,6 +100,8 @@ enum e1000_mac_type { e1000_82576, e1000_82580, e1000_i350, + e1000_i210, + e1000_i211, e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ }; @@ -117,6 +136,7 @@ enum e1000_phy_type { e1000_phy_igp_3, e1000_phy_ife, e1000_phy_82580, + e1000_phy_i210, }; enum e1000_bus_type { @@ -313,6 +333,9 @@ struct e1000_mac_operations { void (*rar_set)(struct e1000_hw *, u8 *, u32); s32 (*read_mac_addr)(struct e1000_hw *); s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *); + s32 (*acquire_swfw_sync)(struct e1000_hw *, u16); + void (*release_swfw_sync)(struct e1000_hw *, u16); + }; struct e1000_phy_operations { @@ -338,6 +361,7 @@ struct e1000_nvm_operations { s32 (*write)(struct e1000_hw *, u16, u16, u16 *); s32 (*update)(struct e1000_hw *); s32 (*validate)(struct e1000_hw *); + s32 (*valid_led_default)(struct e1000_hw *, u16 *); }; struct e1000_info { diff --git a/drivers/net/igb/e1000_i210.c b/drivers/net/igb/e1000_i210.c new file mode 100644 index 000000000000..77a5f939bc74 --- /dev/null +++ b/drivers/net/igb/e1000_i210.c @@ -0,0 +1,603 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007-2012 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ + +/* e1000_i210 + * e1000_i211 + */ + +#include <linux/types.h> +#include <linux/if_ether.h> + +#include "e1000_hw.h" +#include "e1000_i210.h" + +static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw); +static void igb_put_hw_semaphore_i210(struct e1000_hw *hw); +static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data); +static s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw); + +/** + * igb_acquire_nvm_i210 - Request for access to EEPROM + * @hw: pointer to the HW structure + * + * Acquire the necessary semaphores for exclusive access to the EEPROM. + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -E1000_ERR_NVM (-1). + **/ +s32 igb_acquire_nvm_i210(struct e1000_hw *hw) +{ + return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); +} + +/** + * igb_release_nvm_i210 - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit, + * then release the semaphores acquired. + **/ +void igb_release_nvm_i210(struct e1000_hw *hw) +{ + igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); +} + +/** + * igb_acquire_swfw_sync_i210 - Acquire SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Acquire the SW/FW semaphore to access the PHY or NVM. The mask + * will also specify which port we're acquiring the lock for. + **/ +s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + u32 swmask = mask; + u32 fwmask = mask << 16; + s32 ret_val = E1000_SUCCESS; + s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ + + while (i < timeout) { + if (igb_get_hw_semaphore_i210(hw)) { + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync = rd32(E1000_SW_FW_SYNC); + if (!(swfw_sync & fwmask)) + break; + + /* + * Firmware currently using resource (fwmask) + */ + igb_put_hw_semaphore_i210(hw); + mdelay(5); + i++; + } + + if (i == timeout) { + hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n"); + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync |= swmask; + wr32(E1000_SW_FW_SYNC, swfw_sync); + + igb_put_hw_semaphore_i210(hw); +out: + return ret_val; +} + +/** + * igb_release_swfw_sync_i210 - Release SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Release the SW/FW semaphore used to access the PHY or NVM. The mask + * will also specify which port we're releasing the lock for. + **/ +void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + + while (igb_get_hw_semaphore_i210(hw) != E1000_SUCCESS) + ; /* Empty */ + + swfw_sync = rd32(E1000_SW_FW_SYNC); + swfw_sync &= ~mask; + wr32(E1000_SW_FW_SYNC, swfw_sync); + + igb_put_hw_semaphore_i210(hw); +} + +/** + * igb_get_hw_semaphore_i210 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) +{ + u32 swsm; + s32 ret_val = E1000_SUCCESS; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = rd32(E1000_SWSM); + wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI) + break; + + udelay(50); + } + + if (i == timeout) { + /* Release semaphores */ + igb_put_hw_semaphore(hw); + hw_dbg("Driver can't access the NVM\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * igb_put_hw_semaphore_i210 - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +static void igb_put_hw_semaphore_i210(struct e1000_hw *hw) +{ + u32 swsm; + + swsm = rd32(E1000_SWSM); + + swsm &= ~E1000_SWSM_SWESMBI; + + wr32(E1000_SWSM, swsm); +} + +/** + * igb_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register + * @hw: pointer to the HW structure + * @offset: offset of word in the Shadow Ram to read + * @words: number of words to read + * @data: word read from the Shadow Ram + * + * Reads a 16 bit word from the Shadow Ram using the EERD register. + * Uses necessary synchronization semaphores. + **/ +s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 status = E1000_SUCCESS; + u16 i, count; + + /* We cannot hold synchronization semaphores for too long, + * because of forceful takeover procedure. However it is more efficient + * to read in bursts than synchronizing access for each word. */ + for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { + count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? + E1000_EERD_EEWR_MAX_COUNT : (words - i); + if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + status = igb_read_nvm_eerd(hw, offset, count, + data + i); + hw->nvm.ops.release(hw); + } else { + status = E1000_ERR_SWFW_SYNC; + } + + if (status != E1000_SUCCESS) + break; + } + + return status; +} + +/** + * igb_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR + * @hw: pointer to the HW structure + * @offset: offset within the Shadow RAM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the Shadow RAM + * + * Writes data to Shadow RAM at offset using EEWR register. + * + * If e1000_update_nvm_checksum is not called after this function , the + * data will not be committed to FLASH and also Shadow RAM will most likely + * contain an invalid checksum. + * + * If error code is returned, data and Shadow RAM may be inconsistent - buffer + * partially written. + **/ +s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 status = E1000_SUCCESS; + u16 i, count; + + /* We cannot hold synchronization semaphores for too long, + * because of forceful takeover procedure. However it is more efficient + * to write in bursts than synchronizing access for each word. */ + for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { + count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? + E1000_EERD_EEWR_MAX_COUNT : (words - i); + if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + status = igb_write_nvm_srwr(hw, offset, count, + data + i); + hw->nvm.ops.release(hw); + } else { + status = E1000_ERR_SWFW_SYNC; + } + + if (status != E1000_SUCCESS) + break; + } + + return status; +} + +/** + * igb_write_nvm_srwr - Write to Shadow Ram using EEWR + * @hw: pointer to the HW structure + * @offset: offset within the Shadow Ram to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the Shadow Ram + * + * Writes data to Shadow Ram at offset using EEWR register. + * + * If igb_update_nvm_checksum is not called after this function , the + * Shadow Ram will most likely contain an invalid checksum. + **/ +static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i, k, eewr = 0; + u32 attempts = 100000; + s32 ret_val = E1000_SUCCESS; + + /* + * A check for invalid values: offset too large, too many words, + * too many words for the offset, and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + for (i = 0; i < words; i++) { + eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | + (data[i] << E1000_NVM_RW_REG_DATA) | + E1000_NVM_RW_REG_START; + + wr32(E1000_SRWR, eewr); + + for (k = 0; k < attempts; k++) { + if (E1000_NVM_RW_REG_DONE & + rd32(E1000_SRWR)) { + ret_val = E1000_SUCCESS; + break; + } + udelay(5); + } + + if (ret_val != E1000_SUCCESS) { + hw_dbg("Shadow RAM write EEWR timed out\n"); + break; + } + } + +out: + return ret_val; +} + +/** + * igb_read_nvm_i211 - Read NVM wrapper function for I211 + * @hw: pointer to the HW structure + * @address: the word address (aka eeprom offset) to read + * @data: pointer to the data read + * + * Wrapper function to return data formerly found in the NVM. + **/ +s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 ret_val = E1000_SUCCESS; + + /* Only the MAC addr is required to be present in the iNVM */ + switch (offset) { + case NVM_MAC_ADDR: + ret_val = igb_read_invm_i211(hw, offset, &data[0]); + ret_val |= igb_read_invm_i211(hw, offset+1, &data[1]); + ret_val |= igb_read_invm_i211(hw, offset+2, &data[2]); + if (ret_val != E1000_SUCCESS) + hw_dbg("MAC Addr not found in iNVM\n"); + break; + case NVM_ID_LED_SETTINGS: + case NVM_INIT_CTRL_2: + case NVM_INIT_CTRL_4: + case NVM_LED_1_CFG: + case NVM_LED_0_2_CFG: + igb_read_invm_i211(hw, offset, data); + break; + case NVM_COMPAT: + *data = ID_LED_DEFAULT_I210; + break; + case NVM_SUB_DEV_ID: + *data = hw->subsystem_device_id; + break; + case NVM_SUB_VEN_ID: + *data = hw->subsystem_vendor_id; + break; + case NVM_DEV_ID: + *data = hw->device_id; + break; + case NVM_VEN_ID: + *data = hw->vendor_id; + break; + default: + hw_dbg("NVM word 0x%02x is not mapped.\n", offset); + *data = NVM_RESERVED_WORD; + break; + } + return ret_val; +} + +/** + * igb_read_invm_i211 - Reads OTP + * @hw: pointer to the HW structure + * @address: the word address (aka eeprom offset) to read + * @data: pointer to the data read + * + * Reads 16-bit words from the OTP. Return error when the word is not + * stored in OTP. + **/ +s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data) +{ + s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND; + u32 invm_dword; + u16 i; + u8 record_type, word_address; + + for (i = 0; i < E1000_INVM_SIZE; i++) { + invm_dword = rd32(E1000_INVM_DATA_REG(i)); + /* Get record type */ + record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword); + if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE) + break; + if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE) + i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS; + if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE) + i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS; + if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) { + word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword); + if (word_address == (u8)address) { + *data = INVM_DWORD_TO_WORD_DATA(invm_dword); + hw_dbg("Read INVM Word 0x%02x = %x", + address, *data); + status = E1000_SUCCESS; + break; + } + } + } + if (status != E1000_SUCCESS) + hw_dbg("Requested word 0x%02x not found in OTP\n", address); + return status; +} + +/** + * igb_validate_nvm_checksum_i210 - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw) +{ + s32 status = E1000_SUCCESS; + s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *); + + if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + + /* + * Replace the read function with semaphore grabbing with + * the one that skips this for a while. + * We have semaphore taken already here. + */ + read_op_ptr = hw->nvm.ops.read; + hw->nvm.ops.read = igb_read_nvm_eerd; + + status = igb_validate_nvm_checksum(hw); + + /* Revert original read operation. */ + hw->nvm.ops.read = read_op_ptr; + + hw->nvm.ops.release(hw); + } else { + status = E1000_ERR_SWFW_SYNC; + } + + return status; +} + + +/** + * igb_update_nvm_checksum_i210 - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. Next commit EEPROM data onto the Flash. + **/ +s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 checksum = 0; + u16 i, nvm_data; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + ret_val = igb_read_nvm_eerd(hw, 0, 1, &nvm_data); + if (ret_val != E1000_SUCCESS) { + hw_dbg("EEPROM read failed\n"); + goto out; + } + + if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + /* + * Do not use hw->nvm.ops.write, hw->nvm.ops.read + * because we do not want to take the synchronization + * semaphores twice here. + */ + + for (i = 0; i < NVM_CHECKSUM_REG; i++) { + ret_val = igb_read_nvm_eerd(hw, i, 1, &nvm_data); + if (ret_val) { + hw->nvm.ops.release(hw); + hw_dbg("NVM Read Error while updating checksum.\n"); + goto out; + } + checksum += nvm_data; + } + checksum = (u16) NVM_SUM - checksum; + ret_val = igb_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, + &checksum); + if (ret_val != E1000_SUCCESS) { + hw->nvm.ops.release(hw); + hw_dbg("NVM Write Error while updating checksum.\n"); + goto out; + } + + hw->nvm.ops.release(hw); + + ret_val = igb_update_flash_i210(hw); + } else { + ret_val = -E1000_ERR_SWFW_SYNC; + } +out: + return ret_val; +} + +/** + * igb_update_flash_i210 - Commit EEPROM to the flash + * @hw: pointer to the HW structure + * + **/ +s32 igb_update_flash_i210(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u32 flup; + + ret_val = igb_pool_flash_update_done_i210(hw); + if (ret_val == -E1000_ERR_NVM) { + hw_dbg("Flash update time out\n"); + goto out; + } + + flup = rd32(E1000_EECD) | E1000_EECD_FLUPD_I210; + wr32(E1000_EECD, flup); + + ret_val = igb_pool_flash_update_done_i210(hw); + if (ret_val == E1000_SUCCESS) + hw_dbg("Flash update complete\n"); + else + hw_dbg("Flash update time out\n"); + +out: + return ret_val; +} + +/** + * igb_pool_flash_update_done_i210 - Pool FLUDONE status. + * @hw: pointer to the HW structure + * + **/ +s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw) +{ + s32 ret_val = -E1000_ERR_NVM; + u32 i, reg; + + for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) { + reg = rd32(E1000_EECD); + if (reg & E1000_EECD_FLUDONE_I210) { + ret_val = E1000_SUCCESS; + break; + } + udelay(5); + } + + return ret_val; +} + +/** + * igb_valid_led_default_i210 - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg("NVM Read Error\n"); + goto out; + } + + if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { + switch (hw->phy.media_type) { + case e1000_media_type_internal_serdes: + *data = ID_LED_DEFAULT_I210_SERDES; + break; + case e1000_media_type_copper: + default: + *data = ID_LED_DEFAULT_I210; + break; + } + } +out: + return ret_val; +} diff --git a/drivers/net/igb/e1000_i210.h b/drivers/net/igb/e1000_i210.h new file mode 100644 index 000000000000..5dc2bd3f50bc --- /dev/null +++ b/drivers/net/igb/e1000_i210.h @@ -0,0 +1,76 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007-2012 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_I210_H_ +#define _E1000_I210_H_ + +extern s32 igb_update_flash_i210(struct e1000_hw *hw); +extern s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw); +extern s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw); +extern s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +extern s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +extern s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data); +extern s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask); +extern void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask); +extern s32 igb_acquire_nvm_i210(struct e1000_hw *hw); +extern void igb_release_nvm_i210(struct e1000_hw *hw); +extern s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data); +extern s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data); + +#define E1000_STM_OPCODE 0xDB00 +#define E1000_EEPROM_FLASH_SIZE_WORD 0x11 + +#define INVM_DWORD_TO_RECORD_TYPE(invm_dword) \ + (u8)((invm_dword) & 0x7) +#define INVM_DWORD_TO_WORD_ADDRESS(invm_dword) \ + (u8)(((invm_dword) & 0x0000FE00) >> 9) +#define INVM_DWORD_TO_WORD_DATA(invm_dword) \ + (u16)(((invm_dword) & 0xFFFF0000) >> 16) + +enum E1000_INVM_STRUCTURE_TYPE { + E1000_INVM_UNINITIALIZED_STRUCTURE = 0x00, + E1000_INVM_WORD_AUTOLOAD_STRUCTURE = 0x01, + E1000_INVM_CSR_AUTOLOAD_STRUCTURE = 0x02, + E1000_INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE = 0x03, + E1000_INVM_RSA_KEY_SHA256_STRUCTURE = 0x04, + E1000_INVM_INVALIDATED_STRUCTURE = 0x0F, +}; + +#define E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8 +#define E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1 + +#define ID_LED_DEFAULT_I210 ((ID_LED_OFF1_ON2 << 8) | \ + (ID_LED_OFF1_OFF2 << 4) | \ + (ID_LED_DEF1_DEF2)) +#define ID_LED_DEFAULT_I210_SERDES ((ID_LED_DEF1_DEF2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) + +#endif diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 2b5ef761d2ab..c3ee7b21ab4e 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -596,6 +596,7 @@ s32 igb_setup_link(struct e1000_hw *hw) ret_val = igb_set_fc_watermarks(hw); out: + return ret_val; } diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c index 40407124e722..38047a584605 100644 --- a/drivers/net/igb/e1000_nvm.c +++ b/drivers/net/igb/e1000_nvm.c @@ -710,4 +710,3 @@ s32 igb_update_nvm_checksum(struct e1000_hw *hw) out: return ret_val; } - diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index e662554c62d6..d9e0ec065cf7 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c @@ -35,6 +35,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw); static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); static s32 igb_wait_autoneg(struct e1000_hw *hw); +static s32 igb_set_master_slave_mode(struct e1000_hw *hw); /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = @@ -564,6 +565,11 @@ s32 igb_copper_link_setup_m88(struct e1000_hw *hw) hw_dbg("Error committing the PHY changes\n"); goto out; } + if (phy->type == e1000_phy_i210) { + ret_val = igb_set_master_slave_mode(hw); + if (ret_val) + return ret_val; + } out: return ret_val; @@ -1207,12 +1213,22 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) goto out; if (!link) { - if (hw->phy.type != e1000_phy_m88 || - hw->phy.id == I347AT4_E_PHY_ID || - hw->phy.id == M88E1112_E_PHY_ID) { + bool reset_dsp = true; + + switch (hw->phy.id) { + case I347AT4_E_PHY_ID: + case M88E1112_E_PHY_ID: + case I210_I_PHY_ID: + reset_dsp = false; + break; + default: + if (hw->phy.type != e1000_phy_m88) + reset_dsp = false; + break; + } + if (!reset_dsp) hw_dbg("Link taking longer than expected.\n"); - } else { - + else { /* * We didn't get link. * Reset the DSP and cross our fingers. @@ -1237,7 +1253,8 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) if (hw->phy.type != e1000_phy_m88 || hw->phy.id == I347AT4_E_PHY_ID || - hw->phy.id == M88E1112_E_PHY_ID) + hw->phy.id == M88E1112_E_PHY_ID || + hw->phy.id == I210_I_PHY_ID) goto out; ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); @@ -1435,6 +1452,7 @@ s32 igb_check_downshift(struct e1000_hw *hw) u16 phy_data, offset, mask; switch (phy->type) { + case e1000_phy_i210: case e1000_phy_m88: case e1000_phy_gg82563: offset = M88E1000_PHY_SPEC_STATUS; @@ -1470,7 +1488,7 @@ out: * * Polarity is determined based on the PHY specific status register. **/ -static s32 igb_check_polarity_m88(struct e1000_hw *hw) +s32 igb_check_polarity_m88(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; s32 ret_val; @@ -1659,6 +1677,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw) u16 phy_data, phy_data2, index, default_page, is_cm; switch (hw->phy.id) { + case I210_I_PHY_ID: case I347AT4_E_PHY_ID: /* Remember the original page select and set it to 7 */ ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT, @@ -2123,10 +2142,16 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw) void igb_power_up_phy_copper(struct e1000_hw *hw) { u16 mii_reg = 0; + u16 power_reg = 0; /* The PHY will retain its settings across a power down/up cycle */ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); mii_reg &= ~MII_CR_POWER_DOWN; + if (hw->phy.type == e1000_phy_i210) { + hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg); + power_reg &= ~GS40G_CS_POWER_DOWN; + hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg); + } hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); } @@ -2140,10 +2165,18 @@ void igb_power_up_phy_copper(struct e1000_hw *hw) void igb_power_down_phy_copper(struct e1000_hw *hw) { u16 mii_reg = 0; + u16 power_reg = 0; /* The PHY will retain its settings across a power down/up cycle */ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; + + /* i210 Phy requires an additional bit for power up/down */ + if (hw->phy.type == e1000_phy_i210) { + hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg); + power_reg |= GS40G_CS_POWER_DOWN; + hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg); + } hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); msleep(1); } @@ -2339,3 +2372,103 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw) out: return ret_val; } + +/** + * igb_write_phy_reg_gs40g - Write GS40G PHY register + * @hw: pointer to the HW structure + * @offset: lower half is register offset to write to + * upper half is page to use. + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u16 page = offset >> GS40G_PAGE_SHIFT; + + offset = offset & GS40G_OFFSET_MASK; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + + ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page); + if (ret_val) + goto release; + ret_val = igb_write_phy_reg_mdic(hw, offset, data); + +release: + hw->phy.ops.release(hw); + return ret_val; +} + +/** + * igb_read_phy_reg_gs40g - Read GS40G PHY register + * @hw: pointer to the HW structure + * @offset: lower half is register offset to read to + * upper half is page to use. + * @data: data to read at register offset + * + * Acquires semaphore, if necessary, then reads the data in the PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u16 page = offset >> GS40G_PAGE_SHIFT; + + offset = offset & GS40G_OFFSET_MASK; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + + ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page); + if (ret_val) + goto release; + ret_val = igb_read_phy_reg_mdic(hw, offset, data); + +release: + hw->phy.ops.release(hw); + return ret_val; +} + +/** + * igb_set_master_slave_mode - Setup PHY for Master/slave mode + * @hw: pointer to the HW structure + * + * Sets up Master/slave mode + **/ +static s32 igb_set_master_slave_mode(struct e1000_hw *hw) +{ + s32 ret_val; + u16 phy_data; + + /* Resolve Master/Slave mode */ + ret_val = hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, &phy_data); + if (ret_val) + return ret_val; + + /* load defaults for future use */ + hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ? + ((phy_data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : + e1000_ms_force_slave) : e1000_ms_auto; + + switch (hw->phy.ms_type) { + case e1000_ms_force_master: + phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + phy_data |= CR_1000T_MS_ENABLE; + phy_data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + phy_data &= ~CR_1000T_MS_ENABLE; + /* fall-through */ + default: + break; + } + + return hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data); +} diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h index 8510797b9d81..3b813a8bdf1a 100644 --- a/drivers/net/igb/e1000_phy.h +++ b/drivers/net/igb/e1000_phy.h @@ -73,6 +73,9 @@ s32 igb_copper_link_setup_82580(struct e1000_hw *hw); s32 igb_get_phy_info_82580(struct e1000_hw *hw); s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw); s32 igb_get_cable_length_82580(struct e1000_hw *hw); +s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data); +s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data); +s32 igb_check_polarity_m88(struct e1000_hw *hw); /* IGP01E1000 Specific Registers */ #define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ @@ -114,6 +117,13 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw); /* I82580 PHY Diagnostics Status */ #define I82580_DSTATUS_CABLE_LENGTH 0x03FC #define I82580_DSTATUS_CABLE_LENGTH_SHIFT 2 + +/* 82580 PHY Power Management */ +#define E1000_82580_PHY_POWER_MGMT 0xE14 +#define E1000_82580_PM_SPD 0x0001 /* Smart Power Down */ +#define E1000_82580_PM_D0_LPLU 0x0002 /* For D0a states */ +#define E1000_82580_PM_D3_LPLU 0x0004 /* For all other states */ + /* Enable flexible speed on link-up */ #define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ #define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ @@ -133,4 +143,16 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw); #define E1000_CABLE_LENGTH_UNDEFINED 0xFF +/* GS40G - I210 PHY defines */ +#define GS40G_PAGE_SELECT 0x16 +#define GS40G_PAGE_SHIFT 16 +#define GS40G_OFFSET_MASK 0xFFFF +#define GS40G_PAGE_2 0x20000 +#define GS40G_MAC_REG2 0x15 +#define GS40G_MAC_LB 0x4140 +#define GS40G_MAC_SPEED_1G 0X0006 +#define GS40G_COPPER_SPEC 0x0010 +#define GS40G_CS_POWER_DOWN 0x0002 +#define GS40G_LINE_LB 0x4000 + #endif diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index 0990f6d860c7..bb62cf641318 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -351,4 +351,18 @@ #define E1000_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */ #define E1000_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */ +#define E1000_SRWR 0x12018 /* Shadow Ram Write Register - RW */ +#define E1000_I210_FLMNGCTL 0x12038 +#define E1000_I210_FLMNGDATA 0x1203C +#define E1000_I210_FLMNGCNT 0x12040 + +#define E1000_I210_FLSWCTL 0x12048 +#define E1000_I210_FLSWDATA 0x1204C +#define E1000_I210_FLSWCNT 0x12050 + +#define E1000_I210_FLA 0x1201C + +#define E1000_INVM_DATA_REG(_n) (0x12120 + 4*(_n)) +#define E1000_INVM_SIZE 64 /* Number of INVM Data Registers */ + #endif diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 265e151b66c4..111236008d16 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -61,11 +61,14 @@ struct igb_adapter; #define MAX_Q_VECTORS 8 /* Transmit and receive queues */ -#define IGB_MAX_RX_QUEUES (adapter->vfs_allocated_count ? 2 : \ - (hw->mac.type > e1000_82575 ? 8 : 4)) +#define IGB_MAX_RX_QUEUES ((adapter->vfs_allocated_count ? 2 : \ + (hw->mac.type > e1000_82575 ? 8 : 4))) +#define IGB_MAX_RX_QUEUES_I210 4 +#define IGB_MAX_RX_QUEUES_I211 2 #define IGB_ABS_MAX_TX_QUEUES 8 -#define IGB_MAX_TX_QUEUES IGB_MAX_RX_QUEUES - +#define IGB_MAX_TX_QUEUES 16 +#define IGB_MAX_TX_QUEUES_I210 4 +#define IGB_MAX_TX_QUEUES_I211 2 #define IGB_MAX_VF_MC_ENTRIES 30 #define IGB_MAX_VF_FUNCTIONS 8 #define IGB_MAX_VFTA_ENTRIES 128 @@ -227,8 +230,9 @@ struct igb_ring { }; }; -#define IGB_RING_FLAG_RX_CSUM 0x00000001 /* RX CSUM enabled */ -#define IGB_RING_FLAG_RX_SCTP_CSUM 0x00000002 /* SCTP CSUM offload enabled */ +#define IGB_RING_FLAG_RX_CSUM 0x00000001 /* RX CSUM enabled */ +#define IGB_RING_FLAG_RX_SCTP_CSUM 0x00000002 /* SCTP CSUM offload enabled */ +#define IGB_RING_FLAG_RX_LB_VLAN_BSWAP 0x00000003 #define IGB_RING_FLAG_TX_CTX_IDX 0x00000001 /* HW requires context index */ diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 414b0225be89..c9e3d65bd71d 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -549,10 +549,13 @@ static void igb_get_regs(struct net_device *netdev, regs_buff[548] = rd32(E1000_TDFT); regs_buff[549] = rd32(E1000_TDFHS); regs_buff[550] = rd32(E1000_TDFPC); - regs_buff[551] = adapter->stats.o2bgptc; - regs_buff[552] = adapter->stats.b2ospc; - regs_buff[553] = adapter->stats.o2bspc; - regs_buff[554] = adapter->stats.b2ogprc; + + if (hw->mac.type > e1000_82580) { + regs_buff[551] = adapter->stats.o2bgptc; + regs_buff[552] = adapter->stats.b2ospc; + regs_buff[553] = adapter->stats.o2bspc; + regs_buff[554] = adapter->stats.b2ogprc; + } } static int igb_get_eeprom_len(struct net_device *netdev) @@ -621,6 +624,9 @@ static int igb_set_eeprom(struct net_device *netdev, if (eeprom->len == 0) return -EOPNOTSUPP; + if (hw->mac.type == e1000_i211) + return -EOPNOTSUPP; + if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) return -EFAULT; @@ -855,6 +861,36 @@ struct igb_reg_test { #define TABLE64_TEST_LO 5 #define TABLE64_TEST_HI 6 +/* i210 reg test */ +static struct igb_reg_test reg_test_i210[] = { + { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + /* RDH is read-only for i210, only test RDT. */ + { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, + { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, + { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { E1000_TDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, + { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, + { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_RA, 0, 16, TABLE64_TEST_LO, + 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RA, 0, 16, TABLE64_TEST_HI, + 0x900FFFFF, 0xFFFFFFFF }, + { E1000_MTA, 0, 128, TABLE32_TEST, + 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0, 0 } +}; + /* i350 reg test */ static struct igb_reg_test reg_test_i350[] = { { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, @@ -1077,6 +1113,11 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data) test = reg_test_i350; toggle = 0x7FEFF3FF; break; + case e1000_i210: + case e1000_i211: + test = reg_test_i210; + toggle = 0x7FEFF3FF; + break; case e1000_82580: test = reg_test_82580; toggle = 0x7FEFF3FF; @@ -1158,23 +1199,13 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data) static int igb_eeprom_test(struct igb_adapter *adapter, u64 *data) { - u16 temp; - u16 checksum = 0; - u16 i; - *data = 0; - /* Read and add up the contents of the EEPROM */ - for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { - if ((adapter->hw.nvm.ops.read(&adapter->hw, i, 1, &temp)) < 0) { - *data = 1; - break; - } - checksum += temp; - } - /* If Checksum is not Correct return error else test passed */ - if ((checksum != (u16) NVM_SUM) && !(*data)) - *data = 2; + /* Validate eeprom on all parts but i211 */ + if (adapter->hw.mac.type != e1000_i211) { + if (adapter->hw.nvm.ops.validate(&adapter->hw) < 0) + *data = 2; + } return *data; } @@ -1240,6 +1271,8 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) ics_mask = 0x77DCFED5; break; case e1000_i350: + case e1000_i210: + case e1000_i211: ics_mask = 0x77DCFED5; break; default: @@ -1407,23 +1440,35 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; u32 ctrl_reg = 0; + u16 phy_reg = 0; hw->mac.autoneg = false; - if (hw->phy.type == e1000_phy_m88) { + switch (hw->phy.type) { + case e1000_phy_m88: /* Auto-MDI/MDIX Off */ igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* reset to update Auto-MDI/MDIX */ igb_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* autoneg off */ igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); - } else if (hw->phy.type == e1000_phy_82580) { + break; + case e1000_phy_82580: /* enable MII loopback */ igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041); + break; + case e1000_phy_i210: + /* set loopback speed in PHY */ + igb_read_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2), + &phy_reg); + phy_reg |= GS40G_MAC_SPEED_1G; + igb_write_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2), + phy_reg); + ctrl_reg = rd32(E1000_CTRL_EXT); + default: + break; } - ctrl_reg = rd32(E1000_CTRL); - /* force 1000, set loopback */ igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); @@ -1436,7 +1481,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) E1000_CTRL_FD | /* Force Duplex to FULL */ E1000_CTRL_SLU); /* Set link up enable bit */ - if (hw->phy.type == e1000_phy_m88) + if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210)) ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ wr32(E1000_CTRL, ctrl_reg); @@ -1444,7 +1489,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) /* Disable the receiver on the PHY so when a cable is plugged in, the * PHY does not begin to autoneg when a cable is reconnected to the NIC. */ - if (hw->phy.type == e1000_phy_m88) + if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210)) igb_phy_disable_receiver(adapter); udelay(500); @@ -1703,6 +1748,14 @@ static int igb_loopback_test(struct igb_adapter *adapter, u64 *data) *data = 0; goto out; } + if ((adapter->hw.mac.type == e1000_i210) + || (adapter->hw.mac.type == e1000_i210)) { + dev_err(&adapter->pdev->dev, + "Loopback test not supported " + "on this part at this time.\n"); + *data = 0; + goto out; + } *data = igb_setup_desc_rings(adapter); if (*data) goto out; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 40d4c405fd7e..3b1aa4e15df8 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -50,6 +50,7 @@ #ifdef CONFIG_IGB_DCA #include <linux/dca.h> #endif +#include <linux/ctype.h> #include "igb.h" #define MAJ 3 @@ -67,7 +68,15 @@ static const struct e1000_info *igb_info_tbl[] = { [board_82575] = &e1000_82575_info, }; +static char g_mac_addr[ETH_ALEN]; +static int g_usr_mac = 0; + static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES), board_82575 }, @@ -255,6 +264,40 @@ static const struct igb_reg_info igb_reg_info_tbl[] = { {} }; +/* Retrieve user set MAC address */ +static int __init setup_igb_mac(char *macstr) +{ + int i, j; + unsigned char result, value; + + for (i = 0; i < ETH_ALEN; i++) { + result = 0; + + if (i != 5 && *(macstr + 2) != ':') + return -1; + + for (j = 0; j < 2; j++) { + if (isxdigit(*macstr) + && (value = + isdigit(*macstr) ? *macstr - + '0' : toupper(*macstr) - 'A' + 10) < 16) { + result = result * 16 + value; + macstr++; + } else + return -1; + } + + macstr++; + g_mac_addr[i] = result; + } + + g_usr_mac = 1; + + return 0; +} + +__setup("igb_mac=", setup_igb_mac); + /* * igb_regdump - register printout routine */ @@ -647,6 +690,8 @@ static void igb_cache_ring_register(struct igb_adapter *adapter) case e1000_82575: case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: default: for (; i < adapter->num_rx_queues; i++) adapter->rx_ring[i]->reg_idx = rbase_offset + i; @@ -711,6 +756,14 @@ static int igb_alloc_queues(struct igb_adapter *adapter) /* set flag indicating ring supports SCTP checksum offload */ if (adapter->hw.mac.type >= e1000_82576) ring->flags |= IGB_RING_FLAG_RX_SCTP_CSUM; + + /* + * On i350, i210, and i211, loopback VLAN packets + * have the tag byte-swapped. + * */ + if (adapter->hw.mac.type >= e1000_i350) + ring->flags |= IGB_RING_FLAG_RX_LB_VLAN_BSWAP; + adapter->rx_ring[i] = ring; } @@ -791,6 +844,8 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector) break; case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: /* 82580 uses the same table-based approach as 82576 but has fewer entries as a result we carry over for queues greater than 4. */ if (rx_queue > IGB_N0_QUEUE) { @@ -872,6 +927,8 @@ static void igb_configure_msix(struct igb_adapter *adapter) case e1000_82576: case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: /* Turn on MSI-X capability first, or our settings * won't stick. And it will take days to debug. */ wr32(E1000_GPIE, E1000_GPIE_MSIX_MODE | @@ -1018,6 +1075,11 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter) if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS)) numvecs += adapter->num_tx_queues; + /* i210 and i211 can only have 4 MSIX vectors for rx/tx queues. */ + if ((adapter->hw.mac.type == e1000_i210) + || (adapter->hw.mac.type == e1000_i211)) + numvecs = 4; + /* store the number of vectors reserved for queues */ adapter->num_q_vectors = numvecs; @@ -1025,6 +1087,7 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter) numvecs++; adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry), GFP_KERNEL); + if (!adapter->msix_entries) goto msi_only; @@ -1599,6 +1662,8 @@ void igb_reset(struct igb_adapter *adapter) pba &= E1000_RXPBS_SIZE_MASK_82576; break; case e1000_82575: + case e1000_i210: + case e1000_i211: default: pba = E1000_PBA_34K; break; @@ -1839,7 +1904,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, */ if (pdev->is_virtfn) { WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n", - pci_name(pdev), pdev->vendor, pdev->device); + pci_name(pdev), pdev->vendor, pdev->device); return -EINVAL; } @@ -1979,17 +2044,39 @@ static int __devinit igb_probe(struct pci_dev *pdev, * known good starting state */ hw->mac.ops.reset_hw(hw); - /* make sure the NVM is good */ - if (hw->nvm.ops.validate(hw) < 0) { - dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n"); - err = -EIO; - goto err_eeprom; +#ifndef CONFIG_MACH_APALIS_T30 +/* Hack: skip NVM validation on Apalis T30 for now */ + /* + * make sure the NVM is good , i211 parts have special NVM that + * doesn't contain a checksum + */ + if (hw->mac.type != e1000_i211) { + if (hw->nvm.ops.validate(hw) < 0) { + dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } } +#endif /* CONFIG_MACH_APALIS_T30 */ /* copy the MAC address out of the NVM */ if (hw->mac.ops.read_mac_addr(hw)) dev_err(&pdev->dev, "NVM Read Error\n"); +#ifdef CONFIG_MACH_APALIS_T30 + if (g_usr_mac && (g_usr_mac < 3)) { + /* Get user set MAC address */ + if (g_usr_mac == 2) { + /* 0x100000 offset for 2nd Ethernet MAC */ + g_mac_addr[3] += 0x10; + if (g_mac_addr[3] < 0x10) + dev_warn(&pdev->dev, "MAC address byte 3 (0x%02x) wrap around", g_mac_addr[3]); + } + memcpy(hw->mac.addr, g_mac_addr, ETH_ALEN); + g_usr_mac++; + } else dev_warn(&pdev->dev, "using default igb MAC"); +#endif /* CONFIG_MACH_APALIS_T30 */ + memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len); memcpy(netdev->perm_addr, hw->mac.addr, netdev->addr_len); @@ -2117,6 +2204,8 @@ static int __devinit igb_probe(struct pci_dev *pdev, adapter->num_rx_queues, adapter->num_tx_queues); switch (hw->mac.type) { case e1000_i350: + case e1000_i210: + case e1000_i211: igb_set_eee_i350(hw); break; default: @@ -2231,11 +2320,17 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter) { #ifdef CONFIG_PCI_IOV struct pci_dev *pdev = adapter->pdev; + struct e1000_hw *hw = &adapter->hw; + + /* Virtualization features not supported on i210 family. */ + if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) + return; if (adapter->vfs_allocated_count) { adapter->vf_data = kcalloc(adapter->vfs_allocated_count, sizeof(struct vf_data_storage), GFP_KERNEL); + /* if allocation failed then we do not support SR-IOV */ if (!adapter->vf_data) { adapter->vfs_allocated_count = 0; @@ -2409,11 +2504,28 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) } else adapter->vfs_allocated_count = max_vfs; break; + case e1000_i210: + case e1000_i211: + adapter->vfs_allocated_count = 0; + break; default: break; } #endif /* CONFIG_PCI_IOV */ - adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus()); + switch (hw->mac.type) { + case e1000_i210: + adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I210, + num_online_cpus()); + break; + case e1000_i211: + adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I211, + num_online_cpus()); + break; + default: + adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, + num_online_cpus()); + break; + } /* i350 cannot do RSS and SR-IOV at the same time */ if (hw->mac.type == e1000_i350 && adapter->vfs_allocated_count) adapter->rss_queues = 1; @@ -2438,7 +2550,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) /* Explicitly disable IRQ since the NIC can be in any state. */ igb_irq_disable(adapter); - if (hw->mac.type == e1000_i350) + if (hw->mac.type >= e1000_i350) adapter->flags &= ~IGB_FLAG_DMAC; set_bit(__IGB_DOWN, &adapter->state); @@ -2852,6 +2964,17 @@ static void igb_setup_mrqc(struct igb_adapter *adapter) /* Don't need to set TUOFL or IPOFL, they default to 1 */ wr32(E1000_RXCSUM, rxcsum); + /* + * Generate RSS hash based on TCP port numbers and/or + * IPv4/v6 src and dst addresses since UDP cannot be + * hashed reliably due to IP fragmentation + */ + + mrqc = E1000_MRQC_RSS_FIELD_IPV4 | + E1000_MRQC_RSS_FIELD_IPV4_TCP | + E1000_MRQC_RSS_FIELD_IPV6 | + E1000_MRQC_RSS_FIELD_IPV6_TCP | + E1000_MRQC_RSS_FIELD_IPV6_TCP_EX; /* If VMDq is enabled then we set the appropriate mode for that, else * we default to RSS so that an RSS hash is calculated per packet even @@ -2867,25 +2990,15 @@ static void igb_setup_mrqc(struct igb_adapter *adapter) wr32(E1000_VT_CTL, vtctl); } if (adapter->rss_queues > 1) - mrqc = E1000_MRQC_ENABLE_VMDQ_RSS_2Q; + mrqc |= E1000_MRQC_ENABLE_VMDQ_RSS_2Q; else - mrqc = E1000_MRQC_ENABLE_VMDQ; + mrqc |= E1000_MRQC_ENABLE_VMDQ; } else { - mrqc = E1000_MRQC_ENABLE_RSS_4Q; + if (hw->mac.type != e1000_i211) + mrqc |= E1000_MRQC_ENABLE_RSS_4Q; } igb_vmm_control(adapter); - /* - * Generate RSS hash based on TCP port numbers and/or - * IPv4/v6 src and dst addresses since UDP cannot be - * hashed reliably due to IP fragmentation - */ - mrqc |= E1000_MRQC_RSS_FIELD_IPV4 | - E1000_MRQC_RSS_FIELD_IPV4_TCP | - E1000_MRQC_RSS_FIELD_IPV6 | - E1000_MRQC_RSS_FIELD_IPV6_TCP | - E1000_MRQC_RSS_FIELD_IPV6_TCP_EX; - wr32(E1000_MRQC, mrqc); } @@ -3484,7 +3597,7 @@ static void igb_set_rx_mode(struct net_device *netdev) * we will have issues with VLAN tag stripping not being done for frames * that are only arriving because we are the default pool */ - if (hw->mac.type < e1000_82576) + if ((hw->mac.type < e1000_82576) || (hw->mac.type > e1000_i350)) return; vmolr |= rd32(E1000_VMOLR(vfn)) & @@ -3581,7 +3694,7 @@ static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event) bool ret = false; u32 ctrl_ext, thstat; - /* check for thermal sensor event on i350, copper only */ + /* check for thermal sensor event on i350 copper only */ if (hw->mac.type == e1000_i350) { thstat = rd32(E1000_THSTAT); ctrl_ext = rd32(E1000_CTRL_EXT); @@ -6858,6 +6971,8 @@ static void igb_vmm_control(struct igb_adapter *adapter) switch (hw->mac.type) { case e1000_82575: + case e1000_i210: + case e1000_i211: default: /* replication is not supported for 82575 */ return; diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 710557700095..f2d5822338d7 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -1,8 +1,7 @@ /* * ASIX AX8817X based USB 2.0 Ethernet Devices - * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> - * Copyright (C) 2006 James Painter <jamie.painter@iname.com> * Copyright (c) 2002-2003 TiVo Inc. * * This program is free software; you can redistribute it and/or modify @@ -20,11 +19,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// #define DEBUG // error path messages, extra info -// #define VERBOSE // more; success messages +//#define DEBUG // debug messages, extra info +#include <linux/version.h> +//#include <linux/config.h> +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif #include <linux/module.h> #include <linux/kmod.h> +#include <linux/sched.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -33,690 +37,863 @@ #include <linux/mii.h> #include <linux/usb.h> #include <linux/crc32.h> -#include <linux/usb/usbnet.h> -#include <linux/slab.h> -#define DRIVER_VERSION "14-Jun-2006" -static const char driver_name [] = "asix"; - -/* ASIX AX8817X based USB 2.0 Ethernet Devices */ +#include "axusbnet.c" +#include "asix.h" + +#define DRV_VERSION "4.4.0" + +static char version[] = +KERN_INFO "ASIX USB Ethernet Adapter:v" DRV_VERSION + " " __TIME__ " " __DATE__ "\n" +KERN_INFO " http://www.asix.com.tw\n"; + +static char g_mac_addr[ETH_ALEN]; +static int g_usr_mac = 0; + +/* configuration of maximum bulk in size */ +static int bsize = AX88772B_MAX_BULKIN_16K; +module_param (bsize, int, 0); +MODULE_PARM_DESC (bsize, "Maximum transfer size per bulk"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void ax88772b_link_reset (void *data); +static void ax88772a_link_reset (void *data); +static void ax88772_link_reset (void *data); +#else +static void ax88772b_link_reset (struct work_struct *work); +static void ax88772a_link_reset (struct work_struct *work); +static void ax88772_link_reset (struct work_struct *work); +#endif +static int ax88772a_phy_powerup (struct usbnet *dev); + +/* Retrieve user set MAC address */ +static int __init setup_asix_mac(char *macstr) +{ + int i, j; + unsigned char result, value; + + for (i = 0; i < ETH_ALEN; i++) { + result = 0; + + if (i != 5 && *(macstr + 2) != ':') + return -1; + + for (j = 0; j < 2; j++) { + if (isxdigit(*macstr) + && (value = + isdigit(*macstr) ? *macstr - + '0' : toupper(*macstr) - 'A' + 10) < 16) { + result = result * 16 + value; + macstr++; + } else + return -1; + } -#define AX_CMD_SET_SW_MII 0x06 -#define AX_CMD_READ_MII_REG 0x07 -#define AX_CMD_WRITE_MII_REG 0x08 -#define AX_CMD_SET_HW_MII 0x0a -#define AX_CMD_READ_EEPROM 0x0b -#define AX_CMD_WRITE_EEPROM 0x0c -#define AX_CMD_WRITE_ENABLE 0x0d -#define AX_CMD_WRITE_DISABLE 0x0e -#define AX_CMD_READ_RX_CTL 0x0f -#define AX_CMD_WRITE_RX_CTL 0x10 -#define AX_CMD_READ_IPG012 0x11 -#define AX_CMD_WRITE_IPG0 0x12 -#define AX_CMD_WRITE_IPG1 0x13 -#define AX_CMD_READ_NODE_ID 0x13 -#define AX_CMD_WRITE_NODE_ID 0x14 -#define AX_CMD_WRITE_IPG2 0x14 -#define AX_CMD_WRITE_MULTI_FILTER 0x16 -#define AX88172_CMD_READ_NODE_ID 0x17 -#define AX_CMD_READ_PHY_ID 0x19 -#define AX_CMD_READ_MEDIUM_STATUS 0x1a -#define AX_CMD_WRITE_MEDIUM_MODE 0x1b -#define AX_CMD_READ_MONITOR_MODE 0x1c -#define AX_CMD_WRITE_MONITOR_MODE 0x1d -#define AX_CMD_READ_GPIOS 0x1e -#define AX_CMD_WRITE_GPIOS 0x1f -#define AX_CMD_SW_RESET 0x20 -#define AX_CMD_SW_PHY_STATUS 0x21 -#define AX_CMD_SW_PHY_SELECT 0x22 - -#define AX_MONITOR_MODE 0x01 -#define AX_MONITOR_LINK 0x02 -#define AX_MONITOR_MAGIC 0x04 -#define AX_MONITOR_HSFS 0x10 - -/* AX88172 Medium Status Register values */ -#define AX88172_MEDIUM_FD 0x02 -#define AX88172_MEDIUM_TX 0x04 -#define AX88172_MEDIUM_FC 0x10 -#define AX88172_MEDIUM_DEFAULT \ - ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) - -#define AX_MCAST_FILTER_SIZE 8 -#define AX_MAX_MCAST 64 - -#define AX_SWRESET_CLEAR 0x00 -#define AX_SWRESET_RR 0x01 -#define AX_SWRESET_RT 0x02 -#define AX_SWRESET_PRTE 0x04 -#define AX_SWRESET_PRL 0x08 -#define AX_SWRESET_BZ 0x10 -#define AX_SWRESET_IPRL 0x20 -#define AX_SWRESET_IPPD 0x40 - -#define AX88772_IPG0_DEFAULT 0x15 -#define AX88772_IPG1_DEFAULT 0x0c -#define AX88772_IPG2_DEFAULT 0x12 - -/* AX88772 & AX88178 Medium Mode Register */ -#define AX_MEDIUM_PF 0x0080 -#define AX_MEDIUM_JFE 0x0040 -#define AX_MEDIUM_TFC 0x0020 -#define AX_MEDIUM_RFC 0x0010 -#define AX_MEDIUM_ENCK 0x0008 -#define AX_MEDIUM_AC 0x0004 -#define AX_MEDIUM_FD 0x0002 -#define AX_MEDIUM_GM 0x0001 -#define AX_MEDIUM_SM 0x1000 -#define AX_MEDIUM_SBP 0x0800 -#define AX_MEDIUM_PS 0x0200 -#define AX_MEDIUM_RE 0x0100 - -#define AX88178_MEDIUM_DEFAULT \ - (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ - AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ - AX_MEDIUM_RE ) - -#define AX88772_MEDIUM_DEFAULT \ - (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ - AX_MEDIUM_TFC | AX_MEDIUM_PS | \ - AX_MEDIUM_AC | AX_MEDIUM_RE ) - -/* AX88772 & AX88178 RX_CTL values */ -#define AX_RX_CTL_SO 0x0080 -#define AX_RX_CTL_AP 0x0020 -#define AX_RX_CTL_AM 0x0010 -#define AX_RX_CTL_AB 0x0008 -#define AX_RX_CTL_SEP 0x0004 -#define AX_RX_CTL_AMALL 0x0002 -#define AX_RX_CTL_PRO 0x0001 -#define AX_RX_CTL_MFB_2048 0x0000 -#define AX_RX_CTL_MFB_4096 0x0100 -#define AX_RX_CTL_MFB_8192 0x0200 -#define AX_RX_CTL_MFB_16384 0x0300 - -#define AX_DEFAULT_RX_CTL \ - (AX_RX_CTL_SO | AX_RX_CTL_AB ) - -/* GPIO 0 .. 2 toggles */ -#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ -#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ -#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ -#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ -#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ -#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ -#define AX_GPIO_RESERVED 0x40 /* Reserved */ -#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ - -#define AX_EEPROM_MAGIC 0xdeadbeef -#define AX88172_EEPROM_LEN 0x40 -#define AX88772_EEPROM_LEN 0xff - -#define PHY_MODE_MARVELL 0x0000 -#define MII_MARVELL_LED_CTRL 0x0018 -#define MII_MARVELL_STATUS 0x001b -#define MII_MARVELL_CTRL 0x0014 - -#define MARVELL_LED_MANUAL 0x0019 - -#define MARVELL_STATUS_HWCFG 0x0004 - -#define MARVELL_CTRL_TXDELAY 0x0002 -#define MARVELL_CTRL_RXDELAY 0x0080 - -/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct asix_data { - u8 multi_filter[AX_MCAST_FILTER_SIZE]; - u8 mac_addr[ETH_ALEN]; - u8 phymode; - u8 ledmode; - u8 eeprom_len; -}; + macstr++; + g_mac_addr[i] = result; + } -struct ax88172_int_data { - __le16 res1; - u8 link; - __le16 res2; - u8 status; - __le16 res3; -} __packed; + g_usr_mac = 1; -static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) -{ - void *buf; - int err = -ENOMEM; + return 0; +} - netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); +__setup("asix_mac=", setup_asix_mac); - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - goto out; +/* ASIX AX8817X based USB 2.0 Ethernet Devices */ - err = usb_control_msg( +static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + return usb_control_msg( dev->udev, usb_rcvctrlpipe(dev->udev, 0), cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, - buf, + data, size, USB_CTRL_GET_TIMEOUT); - if (err == size) - memcpy(data, buf, size); - else if (err >= 0) - err = -EINVAL; - kfree(buf); - -out: - return err; } -static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { - void *buf = NULL; - int err = -ENOMEM; - - netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - - if (data) { - buf = kmemdup(data, size, GFP_KERNEL); - if (!buf) - goto out; - } - - err = usb_control_msg( + return usb_control_msg( dev->udev, usb_sndctrlpipe(dev->udev, 0), cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, - buf, + data, size, USB_CTRL_SET_TIMEOUT); - kfree(buf); - -out: - return err; } -static void asix_async_cmd_callback(struct urb *urb) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) +#else +static void ax8817x_async_cmd_callback(struct urb *urb) +#endif { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; - int status = urb->status; - if (status < 0) - printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", - status); + if (urb->status < 0) + printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", + urb->status); kfree(req); usb_free_urb(urb); } -static void -asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, - u16 size, void *data) +static int ax8817x_set_mac_addr (struct net_device *net, void *p) { - struct usb_ctrlrequest *req; - int status; - struct urb *urb; + struct usbnet *dev = netdev_priv(net); + struct sockaddr *addr = p; - netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", - cmd, value, index, size); - if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { - netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); + memcpy (net->dev_addr, addr->sa_data, ETH_ALEN); + + /* Set the MAC address */ + return ax8817x_write_cmd (dev, AX88772_CMD_WRITE_NODE_ID, + 0, 0, ETH_ALEN, net->dev_addr); + +} + +static void ax88178_status(struct usbnet *dev, struct urb *urb) +{ + struct ax88172_int_data *event; + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; + int link; + + if (urb->actual_length < 8) return; - } - if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) { - netdev_err(dev->net, "Failed to allocate memory for control request\n"); - usb_free_urb(urb); + if (ax178dataptr->EepromData == PHY_MODE_MAC_TO_MAC_GMII) return; + + event = urb->transfer_buffer; + link = event->link & 0x01; + if (netif_carrier_ok(dev->net) != link) { + if (link) { + netif_carrier_on(dev->net); + axusbnet_defer_kevent (dev, EVENT_LINK_RESET); + } else + netif_carrier_off(dev->net); + devwarn(dev, "ax88178 - Link status is: %d", link); } +} - req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - req->bRequest = cmd; - req->wValue = cpu_to_le16(value); - req->wIndex = cpu_to_le16(index); - req->wLength = cpu_to_le16(size); +static void ax8817x_status(struct usbnet *dev, struct urb *urb) +{ + struct ax88172_int_data *event; + int link; - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)req, data, size, - asix_async_cmd_callback, req); + if (urb->actual_length < 8) + return; - if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - netdev_err(dev->net, "Error submitting the control message: status=%d\n", - status); - kfree(req); - usb_free_urb(urb); + event = urb->transfer_buffer; + link = event->link & 0x01; + if (netif_carrier_ok(dev->net) != link) { + if (link) { + netif_carrier_on(dev->net); + axusbnet_defer_kevent (dev, EVENT_LINK_RESET ); + } else + netif_carrier_off(dev->net); + devwarn(dev, "ax8817x - Link status is: %d", link); } } -static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +static void ax88772_status(struct usbnet *dev, struct urb *urb) { - u8 *head; - u32 header; - char *packet; - struct sk_buff *ax_skb; - u16 size; + struct ax88172_int_data *event; + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; + int link; + + if (urb->actual_length < 8) + return; - head = (u8 *) skb->data; - memcpy(&header, head, sizeof(header)); - le32_to_cpus(&header); - packet = head + sizeof(header); + event = urb->transfer_buffer; + link = event->link & 0x01; + + if (netif_carrier_ok(dev->net) != link) { + if (link) { + netif_carrier_on(dev->net); + ax772_data->Event = AX_SET_RX_CFG; + } else { + netif_carrier_off(dev->net); + if (ax772_data->Event == AX_NOP) { + ax772_data->Event = PHY_POWER_DOWN; + ax772_data->TickToExpire = 25; + } + } - skb_pull(skb, 4); + devwarn(dev, "ax88772 - Link status is: %d", link); + } + + if (ax772_data->Event) + queue_work (ax772_data->ax_work, &ax772_data->check_link); +} - while (skb->len > 0) { - if ((header & 0x07ff) != ((~header >> 16) & 0x07ff)) - netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); +static void ax88772a_status(struct usbnet *dev, struct urb *urb) +{ + struct ax88172_int_data *event; + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; + int link; + int PowSave = (ax772a_data->EepromData >> 14); - /* get the packet length */ - size = (u16) (header & 0x000007ff); + if (urb->actual_length < 8) + return; - if ((skb->len) - ((size + 1) & 0xfffe) == 0) { - u8 alignment = (unsigned long)skb->data & 0x3; - if (alignment != 0x2) { - /* - * not 16bit aligned so use the room provided by - * the 32 bit header to align the data - * - * note we want 16bit alignment as MAC header is - * 14bytes thus ip header will be aligned on - * 32bit boundary so accessing ipheader elements - * using a cast to struct ip header wont cause - * an unaligned accesses. - */ - u8 realignment = (alignment + 2) & 0x3; - memmove(skb->data - realignment, - skb->data, - size); - skb->data -= realignment; - skb_set_tail_pointer(skb, size); - } - return 2; - } + event = urb->transfer_buffer; + link = event->link & 0x01; - if (size > dev->net->mtu + ETH_HLEN) { - netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", - size); - return 0; - } - ax_skb = skb_clone(skb, GFP_ATOMIC); - if (ax_skb) { - u8 alignment = (unsigned long)packet & 0x3; - ax_skb->len = size; + if (netif_carrier_ok(dev->net) != link) { - if (alignment != 0x2) { - /* - * not 16bit aligned use the room provided by - * the 32 bit header to align the data - */ - u8 realignment = (alignment + 2) & 0x3; - memmove(packet - realignment, packet, size); - packet -= realignment; + if (link) { + netif_carrier_on(dev->net); + ax772a_data->Event = AX_SET_RX_CFG; + } else if ((PowSave == 0x3) || (PowSave == 0x1)) { + netif_carrier_off(dev->net); + if (ax772a_data->Event == AX_NOP) { + ax772a_data->Event = CHK_CABLE_EXIST; + ax772a_data->TickToExpire = 14; } - ax_skb->data = packet; - skb_set_tail_pointer(ax_skb, size); - usbnet_skb_return(dev, ax_skb); } else { - return 0; + netif_carrier_off(dev->net); + ax772a_data->Event = AX_NOP; } - skb_pull(skb, (size + 1) & 0xfffe); - - if (skb->len < sizeof(header)) - break; - - head = (u8 *) skb->data; - memcpy(&header, head, sizeof(header)); - le32_to_cpus(&header); - packet = head + sizeof(header); - skb_pull(skb, 4); - } - - if (skb->len < 0) { - netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", - skb->len); - return 0; + devwarn(dev, "ax88772a - Link status is: %d", link); } - return 1; + + if (ax772a_data->Event) + queue_work (ax772a_data->ax_work, &ax772a_data->check_link); } -static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) +static int ax88772b_stop(struct usbnet *dev) { - int padlen; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - u32 packet_len; - u32 padbytes = 0xffff0000; + u16 *medium; - padlen = ((skb->len + 4) % 512) ? 0 : 4; + medium = kmalloc (2, GFP_ATOMIC); + if (medium) { + ax8817x_read_cmd (dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, medium); + ax8817x_write_cmd (dev, AX_CMD_WRITE_MEDIUM_MODE, + (*medium & ~AX88772_MEDIUM_RX_ENABLE), 0, 0, NULL); - if ((!skb_cloned(skb)) && - ((headroom + tailroom) >= (4 + padlen))) { - if ((headroom < 4) || (tailroom < padlen)) { - skb->data = memmove(skb->head + 4, skb->data, skb->len); - skb_set_tail_pointer(skb, skb->len); - } - } else { - struct sk_buff *skb2; - skb2 = skb_copy_expand(skb, 4, padlen, flags); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return NULL; + kfree (medium); + return 0; } + return -EINVAL; + +} - skb_push(skb, 4); - packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); - cpu_to_le32s(&packet_len); - skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); +static int ax88772b_reset(struct usbnet *dev) +{ + int ret; - if ((skb->len % 512) == 0) { - cpu_to_le32s(&padbytes); - memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); - skb_put(skb, sizeof(padbytes)); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + AX88772_MEDIUM_DEFAULT, 0, 0, NULL)) < 0) { + deverr(dev, "Write medium mode register: %d", ret); } - return skb; + return ret; + } -static void asix_status(struct usbnet *dev, struct urb *urb) + +static void ax88772b_status(struct usbnet *dev, struct urb *urb) { + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; struct ax88172_int_data *event; int link; if (urb->actual_length < 8) return; + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) + return; + event = urb->transfer_buffer; - link = event->link & 0x01; + if (ax772b_data->PhySelect == 0 && ax772b_data->OperationMode + == OPERATION_MAC_MODE) + link = event->link & AX_INT_SPLS_LINK; + else + link = event->link & AX_INT_PPLS_LINK; + if (netif_carrier_ok(dev->net) != link) { if (link) { netif_carrier_on(dev->net); - usbnet_defer_kevent (dev, EVENT_LINK_RESET ); - } else + ax772b_data->Event = AX_SET_RX_CFG; + } else { netif_carrier_off(dev->net); - netdev_dbg(dev->net, "Link Status is: %d\n", link); + ax772b_data->time_to_chk = jiffies; + } + devwarn(dev, "ax88772b - Link status is: %d", link); } -} - -static inline int asix_set_sw_mii(struct usbnet *dev) -{ - int ret; - ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to enable software MII access\n"); - return ret; -} -static inline int asix_set_hw_mii(struct usbnet *dev) -{ - int ret; - ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to enable hardware MII access\n"); - return ret; -} + if (!link) { -static inline int asix_get_phy_addr(struct usbnet *dev) -{ - u8 buf[2]; - int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); - - netdev_dbg(dev->net, "asix_get_phy_addr()\n"); + int no_cable = (event->link & AX_INT_CABOFF_UNPLUG) ? 1 : 0; - if (ret < 0) { - netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); - goto out; + if (no_cable) { + if ((ax772b_data->psc & + (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) && + !ax772b_data->pw_enabled) { + /* + * AX88772B already entered power saving state + */ + ax772b_data->pw_enabled = 1; + } +/* Disable failing auto detach stuff for now */ +#if 0 + ax772b_data->Event = AX_CHK_AUTODETACH; +#endif + } else { + /* AX88772B resumed from power saving state */ + if (ax772b_data->pw_enabled || + (jiffies > (ax772b_data->time_to_chk + + AX88772B_WATCHDOG))) { + if (ax772b_data->pw_enabled) + ax772b_data->pw_enabled = 0; + ax772b_data->Event = PHY_POWER_UP; + ax772b_data->time_to_chk = jiffies; + } + } } - netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", - *((__le16 *)buf)); - ret = buf[1]; -out: - return ret; + if (ax772b_data->Event) + queue_work (ax772b_data->ax_work, &ax772b_data->check_link); } -static int asix_sw_reset(struct usbnet *dev, u8 flags) +void +ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) { - int ret; + struct usb_ctrlrequest *req; + int status; + struct urb *urb; - ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); + if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { + deverr(dev, "Error allocating URB in write_cmd_async!"); + return; + } - return ret; -} + if ((req = kmalloc (sizeof (struct usb_ctrlrequest), + GFP_ATOMIC)) == NULL) { + deverr(dev, "Failed to allocate memory for control request"); + usb_free_urb(urb); + return; + } -static u16 asix_read_rx_ctl(struct usbnet *dev) -{ - __le16 v; - int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); + req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + req->bRequest = cmd; + req->wValue = cpu_to_le16(value); + req->wIndex = cpu_to_le16(index); + req->wLength = cpu_to_le16(size); + + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (void *)req, data, size, + ax8817x_async_cmd_callback, req); - if (ret < 0) { - netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); - goto out; + if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + deverr(dev, "Error submitting the control message: status=%d", + status); + kfree(req); + usb_free_urb(urb); } - ret = le16_to_cpu(v); -out: - return ret; } -static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) +static void ax8817x_set_multicast(struct net_device *net) { - int ret; + struct usbnet *dev = netdev_priv(net); + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + u8 rx_ctl = AX_RX_CTL_START | AX_RX_CTL_AB; + int mc_count; - netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", - mode, ret); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + mc_count = net->mc_count; +#else + mc_count = netdev_mc_count (net); +#endif - return ret; -} + if (net->flags & IFF_PROMISC) { + rx_ctl |= AX_RX_CTL_PRO; + } else if (net->flags & IFF_ALLMULTI + || mc_count > AX_MAX_MCAST) { + rx_ctl |= AX_RX_CTL_AMALL; + } else if (mc_count == 0) { + /* just broadcast and directed */ + } else { + /* We use the 20 byte dev->data + * for our 8 byte filter buffer + * to avoid allocating memory that + * is tricky to free later */ + u32 crc_bits; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + struct dev_mc_list *mc_list = net->mc_list; + int i; -static u16 asix_read_medium_status(struct usbnet *dev) -{ - __le16 v; - int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = + ether_crc(ETH_ALEN, + mc_list->dmi_addr) >> 26; + data->multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + mc_list = mc_list->next; + } +#else + struct netdev_hw_addr *ha; + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); + netdev_for_each_mc_addr (ha, net) { + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; + data->multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + } +#endif + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, + AX_MCAST_FILTER_SIZE, data->multi_filter); - if (ret < 0) { - netdev_err(dev->net, "Error reading Medium Status register: %02x\n", - ret); - goto out; + rx_ctl |= AX_RX_CTL_AM; } - ret = le16_to_cpu(v); -out: - return ret; + + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); } -static int asix_write_medium_mode(struct usbnet *dev, u16 mode) +static void ax88178_set_multicast(struct net_device *net) { - int ret; + struct usbnet *dev = netdev_priv(net); + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_MFB); + int mc_count; - netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); - ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", - mode, ret); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + mc_count = net->mc_count; +#else + mc_count = netdev_mc_count (net); +#endif - return ret; -} + if (net->flags & IFF_PROMISC) { + rx_ctl |= AX_RX_CTL_PRO; + } else if (net->flags & IFF_ALLMULTI + || mc_count > AX_MAX_MCAST) { + rx_ctl |= AX_RX_CTL_AMALL; + } else if (mc_count == 0) { + /* just broadcast and directed */ + } else { + /* We use the 20 byte dev->data + * for our 8 byte filter buffer + * to avoid allocating memory that + * is tricky to free later */ + u32 crc_bits; -static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) -{ - int ret; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + struct dev_mc_list *mc_list = net->mc_list; + int i; - netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); - ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); - if (ret < 0) - netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", - value, ret); + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = + ether_crc(ETH_ALEN, + mc_list->dmi_addr) >> 26; + data->multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + mc_list = mc_list->next; + } +#else + struct netdev_hw_addr *ha; + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); + netdev_for_each_mc_addr (ha, net) { + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; + data->multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + } +#endif + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, + AX_MCAST_FILTER_SIZE, data->multi_filter); - if (sleep) - msleep(sleep); + rx_ctl |= AX_RX_CTL_AM; + } - return ret; + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); } -/* - * AX88772 & AX88178 have a 16-bit RX_CTL value - */ -static void asix_set_multicast(struct net_device *net) +static void ax88772b_set_multicast(struct net_device *net) { struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - u16 rx_ctl = AX_DEFAULT_RX_CTL; + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_HEADER_DEFAULT); + int mc_count; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + mc_count = net->mc_count; +#else + mc_count = netdev_mc_count (net); +#endif if (net->flags & IFF_PROMISC) { rx_ctl |= AX_RX_CTL_PRO; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > AX_MAX_MCAST) { + } else if (net->flags & IFF_ALLMULTI + || mc_count > AX_MAX_MCAST) { rx_ctl |= AX_RX_CTL_AMALL; - } else if (netdev_mc_empty(net)) { + } else if (mc_count == 0) { /* just broadcast and directed */ } else { /* We use the 20 byte dev->data * for our 8 byte filter buffer * to avoid allocating memory that * is tricky to free later */ - struct netdev_hw_addr *ha; u32 crc_bits; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + struct dev_mc_list *mc_list = net->mc_list; + int i; + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; + for (i = 0; i < net->mc_count; i++) { + crc_bits = + ether_crc(ETH_ALEN, + mc_list->dmi_addr) >> 26; data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); + mc_list = mc_list->next; } - - asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, +#else + struct netdev_hw_addr *ha; + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); + netdev_for_each_mc_addr (ha, net) { + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; + data->multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + } +#endif + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, AX_MCAST_FILTER_SIZE, data->multi_filter); rx_ctl |= AX_RX_CTL_AM; } - asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); +} + +static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) +{ + struct usbnet *dev = netdev_priv(netdev); + u16 *res; + u16 ret; + + res = kmalloc (2, GFP_ATOMIC); + if (!res) + return 0; + + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); + ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, res); + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); + + ret = *res & 0xffff; + kfree (res); + + return ret; } -static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) +static int +ax8817x_swmii_mdio_read(struct net_device *netdev, int phy_id, int loc) { struct usbnet *dev = netdev_priv(netdev); - __le16 res; + u16 *res; + u16 ret; + + res = kmalloc (2, GFP_ATOMIC); + if (!res) + return 0; + + ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, + (__u16)loc, 2, res); - mutex_lock(&dev->phy_mutex); - asix_set_sw_mii(dev); - asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, - (__u16)loc, 2, &res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); + ret = *res & 0xffff; + kfree (res); - netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", - phy_id, loc, le16_to_cpu(res)); + return ret; +} - return le16_to_cpu(res); +/* same as above, but converts resulting value to cpu byte order */ +static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc) +{ + return le16_to_cpu(ax8817x_mdio_read(netdev,phy_id, loc)); +} + +static int +ax8817x_swmii_mdio_read_le(struct net_device *netdev, int phy_id, int loc) +{ + return le16_to_cpu(ax8817x_swmii_mdio_read(netdev,phy_id, loc)); } static void -asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) +ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) { struct usbnet *dev = netdev_priv(netdev); - __le16 res = cpu_to_le16(val); + u16 *res; + + res = kmalloc (2, GFP_ATOMIC); + if (!res) + return; + *res = val; + + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, + (__u16)loc, 2, res); + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); - netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", - phy_id, loc, val); - mutex_lock(&dev->phy_mutex); - asix_set_sw_mii(dev); - asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); - asix_set_hw_mii(dev); - mutex_unlock(&dev->phy_mutex); + kfree (res); } -/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ -static u32 asix_get_phyid(struct usbnet *dev) +static void ax8817x_swmii_mdio_write(struct net_device *netdev, + int phy_id, int loc, int val) { - int phy_reg; - u32 phy_id; + struct usbnet *dev = netdev_priv(netdev); + u16 *res; - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); - if (phy_reg < 0) - return 0; + res = kmalloc (2, GFP_ATOMIC); + if (!res) + return; + *res = val; - phy_id = (phy_reg & 0xffff) << 16; + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, + (__u16)loc, 2, res); - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); - if (phy_reg < 0) - return 0; + kfree (res); +} + +static void +ax88772b_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) +{ + struct usbnet *dev = netdev_priv(netdev); + u16 *res; + + res = kmalloc (2, GFP_ATOMIC); + if (!res) + return; + *res = val; + + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, + (__u16)loc, 2, res); + + if (loc == MII_ADVERTISE) { + *res = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART); + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, + (__u16)MII_BMCR, 2, res); + } + + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); + + kfree (res); +} + +/* same as above, but converts new value to le16 byte order before writing */ +static void +ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) +{ + ax8817x_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) ); +} + +static void ax8817x_swmii_mdio_write_le(struct net_device *netdev, + int phy_id, int loc, int val) +{ + ax8817x_swmii_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) ); +} + +static void +ax88772b_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) +{ + ax88772b_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) ); +} + +static int ax88772_suspend (struct usb_interface *intf, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) + pm_message_t message) +#else + u32 message) +#endif +{ + struct usbnet *dev = usb_get_intfdata(intf); + u16 *medium; + + medium = kmalloc (2, GFP_ATOMIC); + if (!medium) + return axusbnet_suspend (intf, message); + + ax8817x_read_cmd (dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, medium); + ax8817x_write_cmd (dev, AX_CMD_WRITE_MEDIUM_MODE, + (*medium & ~AX88772_MEDIUM_RX_ENABLE), 0, 0, NULL); + + kfree (medium); + return axusbnet_suspend (intf, message); +} + +static int ax88772b_suspend (struct usb_interface *intf, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) + pm_message_t message) +#else + u32 message) +#endif +{ + struct usbnet *dev = usb_get_intfdata(intf); + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; + u16 *tmp16; + u8 *opt; + + tmp16 = kmalloc (2, GFP_ATOMIC); + if (!tmp16) + return axusbnet_suspend (intf, message); + opt = (u8 *)tmp16; + + ax8817x_read_cmd (dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, tmp16); + ax8817x_write_cmd (dev, AX_CMD_WRITE_MEDIUM_MODE, + (*tmp16 & ~AX88772_MEDIUM_RX_ENABLE), 0, 0, NULL); + + ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, opt); + if (!(*opt & AX_MONITOR_LINK) && !(*opt & AX_MONITOR_MAGIC)) { + ax8817x_write_cmd (dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | AX_SWRESET_IPPD, 0, 0, NULL); + } else { + + if (ax772b_data->psc & AX_SWRESET_WOLLP) { + *tmp16 = ax8817x_mdio_read_le (dev->net, + dev->mii.phy_id, MII_BMCR); + ax8817x_mdio_write_le (dev->net, dev->mii.phy_id, + MII_BMCR, *tmp16 | BMCR_ANENABLE); + + ax8817x_write_cmd (dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | ax772b_data->psc, 0, 0, NULL); + } + + if (ax772b_data->psc & + (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) { + *opt |= AX_MONITOR_LINK; + ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, + *opt, 0, 0, NULL); + } + } + + kfree (tmp16); + return axusbnet_suspend (intf, message); +} - phy_id |= (phy_reg & 0xffff); +static int ax88772_resume (struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + + netif_carrier_off (dev->net); + + return axusbnet_resume (intf); +} + +static int ax88772b_resume (struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; + + if (ax772b_data->psc & AX_SWRESET_WOLLP) { + ax8817x_write_cmd (dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | (ax772b_data->psc & 0x7FFF), + 0, 0, NULL); + } + + if (ax772b_data->psc & (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) { + ax88772a_phy_powerup (dev); + } + + netif_carrier_off (dev->net); + + return axusbnet_resume (intf); +} + +static int ax88172_link_reset(struct usbnet *dev) +{ + u16 lpa; + u16 adv; + u16 res; + u8 mode; + + mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; + lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); + adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); + res = mii_nway_result(lpa|adv); + if (res & LPA_DUPLEX) + mode |= AX_MEDIUM_FULL_DUPLEX; + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); - return phy_id; + return 0; } static void -asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); - u8 opt; + u8 *opt; + + wolinfo->supported = 0; + wolinfo->wolopts = 0; - if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { - wolinfo->supported = 0; - wolinfo->wolopts = 0; + opt = kmalloc (1, GFP_KERNEL); + if (!opt) return; - } + + if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, opt) < 0) + return; + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; - wolinfo->wolopts = 0; - if (opt & AX_MONITOR_MODE) { - if (opt & AX_MONITOR_LINK) - wolinfo->wolopts |= WAKE_PHY; - if (opt & AX_MONITOR_MAGIC) - wolinfo->wolopts |= WAKE_MAGIC; - } + + if (*opt & AX_MONITOR_LINK) + wolinfo->wolopts |= WAKE_PHY; + if (*opt & AX_MONITOR_MAGIC) + wolinfo->wolopts |= WAKE_MAGIC; + + kfree (opt); } static int -asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); - u8 opt = 0; + u8 *opt; + + opt = kmalloc (1, GFP_KERNEL); + if (!opt) + return -ENOMEM; + *opt = 0; if (wolinfo->wolopts & WAKE_PHY) - opt |= AX_MONITOR_LINK; + *opt |= AX_MONITOR_LINK; if (wolinfo->wolopts & WAKE_MAGIC) - opt |= AX_MONITOR_MAGIC; - if (opt != 0) - opt |= AX_MONITOR_MODE; + *opt |= AX_MONITOR_MAGIC; - if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, - opt, 0, 0, NULL) < 0) - return -EINVAL; + ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, *opt, 0, 0, NULL); + kfree (opt); return 0; } -static int asix_get_eeprom_len(struct net_device *net) +static int ax8817x_get_eeprom_len(struct net_device *net) { - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - - return data->eeprom_len; + return AX_EEPROM_LEN; } -static int asix_get_eeprom(struct net_device *net, +static int ax8817x_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data) { struct usbnet *dev = netdev_priv(net); - __le16 *ebuf = (__le16 *)data; + u16 *ebuf = (u16 *)data; int i; /* Crude hack to ensure that we don't overwrite memory @@ -729,722 +906,2765 @@ static int asix_get_eeprom(struct net_device *net, /* ax8817x returns 2 bytes from eeprom on read */ for (i=0; i < eeprom->len / 2; i++) { - if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, + if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, eeprom->offset + i, 0, 2, &ebuf[i]) < 0) return -EINVAL; } return 0; } -static void asix_get_drvinfo (struct net_device *net, +static void ax8817x_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) { - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - /* Inherit standard device info */ - usbnet_get_drvinfo(net, info); - strncpy (info->driver, driver_name, sizeof info->driver); - strncpy (info->version, DRIVER_VERSION, sizeof info->version); - info->eedump_len = data->eeprom_len; + axusbnet_get_drvinfo(net, info); + info->eedump_len = 0x3e; } -static u32 asix_get_link(struct net_device *net) +static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) { struct usbnet *dev = netdev_priv(net); + return mii_ethtool_gset(&dev->mii,cmd); +} - return mii_link_ok(&dev->mii); +static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + return mii_ethtool_sset(&dev->mii,cmd); } -static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) +/* We need to override some ethtool_ops so we require our + own structure so we don't interfere with other usbnet + devices that may be connected at the same time. */ +static struct ethtool_ops ax8817x_ethtool_ops = { + .get_drvinfo = ax8817x_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = axusbnet_get_msglevel, + .set_msglevel = axusbnet_set_msglevel, + .get_wol = ax8817x_get_wol, + .set_wol = ax8817x_set_wol, + .get_eeprom_len = ax8817x_get_eeprom_len, + .get_eeprom = ax8817x_get_eeprom, + .get_settings = ax8817x_get_settings, + .set_settings = ax8817x_set_settings, +}; + +static int ax8817x_ioctl (struct net_device *net, struct ifreq *rq, int cmd) { struct usbnet *dev = netdev_priv(net); return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); } -static int asix_set_mac_address(struct net_device *net, void *p) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) +static const struct net_device_ops ax88x72_netdev_ops = { + .ndo_open = axusbnet_open, + .ndo_stop = axusbnet_stop, + .ndo_start_xmit = axusbnet_start_xmit, + .ndo_tx_timeout = axusbnet_tx_timeout, + .ndo_change_mtu = axusbnet_change_mtu, + .ndo_get_stats = axusbnet_get_stats, + .ndo_do_ioctl = ax8817x_ioctl, + .ndo_set_mac_address = ax8817x_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,2,0) + .ndo_set_multicast_list = ax8817x_set_multicast, +#else + .ndo_set_rx_mode = ax8817x_set_multicast, +#endif +}; +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) +static const struct net_device_ops ax88178_netdev_ops = { + .ndo_open = axusbnet_open, + .ndo_stop = axusbnet_stop, + .ndo_start_xmit = axusbnet_start_xmit, + .ndo_tx_timeout = axusbnet_tx_timeout, + .ndo_change_mtu = axusbnet_change_mtu, + .ndo_get_stats = axusbnet_get_stats, + .ndo_do_ioctl = ax8817x_ioctl, + .ndo_set_mac_address = ax8817x_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,2,0) + .ndo_set_multicast_list = ax88178_set_multicast, +#else + .ndo_set_rx_mode = ax88178_set_multicast, +#endif +}; +#endif + +static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) { - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - struct sockaddr *addr = p; + int ret = 0; + void *buf; + int i; + unsigned long gpio_bits = dev->driver_info->data; + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + + axusbnet_get_endpoints(dev,intf); + + buf = kmalloc(ETH_ALEN, GFP_KERNEL); + if(!buf) { + ret = -ENOMEM; + goto out1; + } + + /* Toggle the GPIOs in a manufacturer/model specific way */ + for (i = 2; i >= 0; i--) { + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + (gpio_bits >> (i * 8)) & 0xff, 0, 0, + NULL)) < 0) + goto out2; + msleep(5); + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + 0x80, 0, 0, NULL)) < 0) { + deverr(dev, "send AX_CMD_WRITE_RX_CTL failed: %d", ret); + goto out2; + } + + /* Get the MAC address */ + memset(buf, 0, ETH_ALEN); + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, + 0, 0, 6, buf)) < 0) { + deverr(dev, "read AX_CMD_READ_NODE_ID failed: %d", ret); + goto out2; + } + memcpy(dev->net->dev_addr, buf, ETH_ALEN); + + /* Get the PHY id */ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, + 0, 0, 2, buf)) < 0) { + deverr(dev, "error on read AX_CMD_READ_PHY_ID: %02x", ret); + goto out2; + } else if (ret < 2) { + /* this should always return 2 bytes */ + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", + ret); + ret = -EIO; + goto out2; + } - if (netif_running(net)) - return -EBUSY; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = ax8817x_mdio_read_le; + dev->mii.mdio_write = ax8817x_mdio_write_le; + dev->mii.phy_id_mask = 0x3f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = *((u8 *)buf + 1); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) + dev->net->do_ioctl = ax8817x_ioctl; + dev->net->set_multicast_list = ax8817x_set_multicast; + dev->net->set_mac_address = ax8817x_set_mac_addr; +#else + dev->net->netdev_ops = &ax88x72_netdev_ops; +#endif - memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); + dev->net->ethtool_ops = &ax8817x_ethtool_ops; + + /* Register suspend and resume functions */ + data->suspend = axusbnet_suspend; + data->resume = axusbnet_resume; + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + mii_nway_restart(&dev->mii); - /* We use the 20 byte dev->data - * for our 6 byte mac buffer - * to avoid allocating memory that - * is tricky to free later */ - memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); - asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, - data->mac_addr); + printk (version); return 0; +out2: + kfree(buf); +out1: + return ret; } -/* We need to override some ethtool_ops so we require our - own structure so we don't interfere with other usbnet - devices that may be connected at the same time. */ -static const struct ethtool_ops ax88172_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, +static struct ethtool_ops ax88772_ethtool_ops = { + .get_drvinfo = ax8817x_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = axusbnet_get_msglevel, + .set_msglevel = axusbnet_set_msglevel, + .get_wol = ax8817x_get_wol, + .set_wol = ax8817x_set_wol, + .get_eeprom_len = ax8817x_get_eeprom_len, + .get_eeprom = ax8817x_get_eeprom, + .get_settings = ax8817x_get_settings, + .set_settings = ax8817x_set_settings, }; -static void ax88172_set_multicast(struct net_device *net) +static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) { - struct usbnet *dev = netdev_priv(net); - struct asix_data *data = (struct asix_data *)&dev->data; - u8 rx_ctl = 0x8c; + int ret; + void *buf; + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + struct ax88772_data *ax772_data = NULL; - if (net->flags & IFF_PROMISC) { - rx_ctl |= 0x01; - } else if (net->flags & IFF_ALLMULTI || - netdev_mc_count(net) > AX_MAX_MCAST) { - rx_ctl |= 0x02; - } else if (netdev_mc_empty(net)) { - /* just broadcast and directed */ - } else { - /* We use the 20 byte dev->data - * for our 8 byte filter buffer - * to avoid allocating memory that - * is tricky to free later */ - struct netdev_hw_addr *ha; - u32 crc_bits; + axusbnet_get_endpoints(dev,intf); - memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); + buf = kmalloc(6, GFP_KERNEL); + if(!buf) { + deverr(dev, "Cannot allocate memory for buffer"); + ret = -ENOMEM; + goto out1; + } - /* Build the multicast hash filter. */ - netdev_for_each_mc_addr(ha, net) { - crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; - data->multi_filter[crc_bits >> 3] |= - 1 << (crc_bits & 7); + ax772_data = kmalloc (sizeof(*ax772_data), GFP_KERNEL); + if (!ax772_data) { + deverr(dev, "Cannot allocate memory for AX88772 data"); + kfree (buf); + return -ENOMEM; + } + memset (ax772_data, 0, sizeof(*ax772_data)); + dev->priv = ax772_data; + + ax772_data->ax_work = create_singlethread_workqueue ("ax88772"); + if (!ax772_data->ax_work) { + kfree (ax772_data); + kfree (buf); + return -ENOMEM; + } + + ax772_data->dev = dev; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK (&ax772_data->check_link, ax88772_link_reset, dev); +#else + INIT_WORK (&ax772_data->check_link, ax88772_link_reset); +#endif + + /* reload eeprom data */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + 0x00B0, 0, 0, NULL)) < 0) + goto out2; + + msleep(5); + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = ax8817x_mdio_read_le; + dev->mii.mdio_write = ax8817x_mdio_write_le; + dev->mii.phy_id_mask = 0xff; + dev->mii.reg_num_mask = 0xff; + + /* Get the PHY id */ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, + 0, 0, 2, buf)) < 0) { + deverr(dev, "Error reading PHY ID: %02x", ret); + goto out2; + } else if (ret < 2) { + /* this should always return 2 bytes */ + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", + ret); + ret = -EIO; + goto out2; + } + dev->mii.phy_id = *((u8 *)buf + 1); + + if (dev->mii.phy_id == 0x10) + { + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, + 0x0001, 0, 0, NULL)) < 0) { + deverr(dev, "Select PHY #1 failed: %d", ret); + goto out2; } - asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, data->multi_filter); + if ((ret = ax8817x_write_cmd (dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD, + 0, 0, NULL)) < 0) { + deverr(dev, "Failed to power down PHY: %d", ret); + goto out2; + } + + msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_CLEAR, + 0, 0, NULL)) < 0) { + deverr(dev, + "Failed to perform software reset: %d", ret); + goto out2; + } + + msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | AX_SWRESET_PRL, + 0, 0, NULL)) < 0) { + deverr(dev, + "Failed to set PHY reset control: %d", ret); + goto out2; + } + } + else + { + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, + 0x0000, 0, 0, NULL)) < 0) { + deverr(dev, "Select PHY #1 failed: %d", ret); + goto out2; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD | AX_SWRESET_PRL, + 0, 0, NULL)) < 0) { + deverr(dev, + "Failed to power down internal PHY: %d", ret); + goto out2; + } + } + + msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + 0x0000, 0, 0, NULL)) < 0) { + deverr(dev, "Failed to reset RX_CTL: %d", ret); + goto out2; + } + + /* Get the MAC address */ + memset(buf, 0, ETH_ALEN); + if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, + 0, 0, ETH_ALEN, buf)) < 0) { + deverr(dev, "Failed to read MAC address: %d", ret); + goto out2; + } + memcpy(dev->net->dev_addr, buf, ETH_ALEN); + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, + 0, 0, 0, NULL)) < 0) { + deverr(dev, "Enabling software MII failed: %d", ret); + goto out2; + } + + if (dev->mii.phy_id == 0x10) + { + if ((ret = ax8817x_mdio_read_le(dev->net, + dev->mii.phy_id, 2)) != 0x003b) { + deverr(dev, "Read PHY register 2 must be 0x3b00: %d", + ret); + goto out2; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_PRL, + 0, 0, NULL)) < 0) { + deverr(dev, "Set external PHY reset pin level: %d", ret); + goto out2; + } + msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | AX_SWRESET_PRL, + 0, 0, NULL)) < 0) { + deverr(dev, + "Set Internal/External PHY reset control: %d", + ret); + goto out2; + } + msleep(150); + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) + dev->net->do_ioctl = ax8817x_ioctl; + dev->net->set_multicast_list = ax8817x_set_multicast; + dev->net->set_mac_address = ax8817x_set_mac_addr; +#else + dev->net->netdev_ops = &ax88x72_netdev_ops; +#endif + + dev->net->ethtool_ops = &ax88772_ethtool_ops; + + /* Register suspend and resume functions */ + data->suspend = ax88772_suspend; + data->resume = ax88772_resume; + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA); - rx_ctl |= 0x10; + mii_nway_restart(&dev->mii); + ax772_data->autoneg_start = jiffies; + ax772_data->Event = WAIT_AUTONEG_COMPLETE; + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + 0, 0, 0, NULL)) < 0) { + deverr(dev, "Write medium mode register: %d", ret); + goto out2; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, + AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT << 8, + AX88772_IPG2_DEFAULT, 0, NULL)) < 0) { + deverr(dev, "Write IPG,IPG1,IPG2 failed: %d", ret); + goto out2; + } + if ((ret = + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL)) < 0) { + deverr(dev, "Failed to set hardware MII: %02x", ret); + goto out2; + } + + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ + if ((ret = + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, + NULL)) < 0) { + deverr(dev, "Reset RX_CTL failed: %d", ret); + goto out2; + } + + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ + if (dev->driver_info->flags & FLAG_FRAMING_AX) { + /* hard_mtu is still the default - the device does not support + jumbo eth frames */ + dev->rx_urb_size = 2048; } - asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); + kfree (buf); + printk (version); + return 0; + +out2: + destroy_workqueue (ax772_data->ax_work); + kfree (ax772_data); + kfree(buf); +out1: + return ret; } -static int ax88172_link_reset(struct usbnet *dev) +static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) { - u8 mode; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88172_MEDIUM_DEFAULT; + if (ax772_data) { - if (ecmd.duplex != DUPLEX_FULL) - mode |= ~AX88172_MEDIUM_FD; + flush_workqueue (ax772_data->ax_work); + destroy_workqueue (ax772_data->ax_work); - netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", - ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); + /* stop MAC operation */ + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + AX_RX_CTL_STOP, 0, 0, NULL); - asix_write_medium_mode(dev, mode); + /* Power down PHY */ + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD, 0, 0, NULL); - return 0; + kfree (ax772_data); + } } -static const struct net_device_ops ax88172_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = asix_ioctl, - .ndo_set_multicast_list = ax88172_set_multicast, -}; +static int ax88772a_phy_powerup (struct usbnet *dev) +{ + int ret; + /* set the embedded Ethernet PHY in power-down state */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD | AX_SWRESET_IPRL, 0, 0, NULL)) < 0) { + deverr(dev, "Failed to power down PHY: %d", ret); + return ret; + } + + msleep(10); + + + /* set the embedded Ethernet PHY in power-up state */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL, 0, 0, NULL)) < 0) { + deverr(dev, "Failed to reset PHY: %d", ret); + return ret; + } + + msleep(600); + + /* set the embedded Ethernet PHY in reset state */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_CLEAR, 0, 0, NULL)) < 0) { + deverr(dev, "Failed to power up PHY: %d", ret); + return ret; + } + + /* set the embedded Ethernet PHY in power-up state */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL, 0, 0, NULL)) < 0) { + deverr(dev, "Failed to reset PHY: %d", ret); + return ret; + } + + return 0; +} -static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) +static int ax88772a_bind(struct usbnet *dev, struct usb_interface *intf) { - int ret = 0; - u8 buf[ETH_ALEN]; - int i; - unsigned long gpio_bits = dev->driver_info->data; - struct asix_data *data = (struct asix_data *)&dev->data; + int ret = -EIO; + void *buf; + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + struct ax88772a_data *ax772a_data = NULL; - data->eeprom_len = AX88172_EEPROM_LEN; + axusbnet_get_endpoints(dev,intf); - usbnet_get_endpoints(dev,intf); + buf = kmalloc(6, GFP_KERNEL); + if(!buf) { + deverr(dev, "Cannot allocate memory for buffer"); + ret = -ENOMEM; + goto out1; + } - /* Toggle the GPIOs in a manufacturer/model specific way */ - for (i = 2; i >= 0; i--) { - if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, - (gpio_bits >> (i * 8)) & 0xff, 0, 0, - NULL)) < 0) - goto out; - msleep(5); + ax772a_data = kmalloc (sizeof(*ax772a_data), GFP_KERNEL); + if (!ax772a_data) { + deverr(dev, "Cannot allocate memory for AX88772A data"); + kfree (buf); + return -ENOMEM; + } + memset (ax772a_data, 0, sizeof(*ax772a_data)); + dev->priv = ax772a_data; + + ax772a_data->ax_work = create_singlethread_workqueue ("ax88772a"); + if (!ax772a_data->ax_work) { + kfree (ax772a_data); + kfree (buf); + return -ENOMEM; + } + + ax772a_data->dev = dev; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK (&ax772a_data->check_link, ax88772a_link_reset, dev); +#else + INIT_WORK (&ax772a_data->check_link, ax88772a_link_reset); +#endif + + /* Get the EEPROM data*/ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, + 0x0017, 0, 2, (void *)&ax772a_data->EepromData)) < 0) { + deverr(dev, "read SROM address 17h failed: %d", ret); + goto out2; + } + le16_to_cpus (&ax772a_data->EepromData); + /* End of get EEPROM data */ + + /* reload eeprom data */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + AXGPIOS_RSE, 0, 0, NULL)) < 0) + goto out2; + + msleep(5); + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = ax8817x_mdio_read_le; + dev->mii.mdio_write = ax8817x_mdio_write_le; + dev->mii.phy_id_mask = 0xff; + dev->mii.reg_num_mask = 0xff; + + /* Get the PHY id */ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, + 0, 0, 2, buf)) < 0) { + deverr(dev, "Error reading PHY ID: %02x", ret); + goto out2; + } else if (ret < 2) { + /* this should always return 2 bytes */ + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", + ret); + goto out2; + } + dev->mii.phy_id = *((u8 *)buf + 1); + + if(dev->mii.phy_id != 0x10) { + deverr(dev, "Got wrong PHY ID: %02x", dev->mii.phy_id); + goto out2; + } + + /* select the embedded 10/100 Ethernet PHY */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, + AX_PHYSEL_SSEN | AX_PHYSEL_PSEL | AX_PHYSEL_SSMII, + 0, 0, NULL)) < 0) { + deverr(dev, "Select PHY #1 failed: %d", ret); + goto out2; } - if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0) - goto out; + if ((ret = ax88772a_phy_powerup (dev)) < 0) + goto out2; + + /* stop MAC operation */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + AX_RX_CTL_STOP, 0, 0, NULL)) < 0) { + deverr(dev, "Reset RX_CTL failed: %d", ret); + goto out2; + } /* Get the MAC address */ - if ((ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, + memset(buf, 0, ETH_ALEN); + if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { - dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); - goto out; + deverr(dev, "Failed to read MAC address: %d", ret); + goto out2; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x3f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = asix_get_phy_addr(dev); + /* make sure the driver can enable sw mii operation */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, + 0, 0, 0, NULL)) < 0) { + deverr(dev, "Enabling software MII failed: %d", ret); + goto out2; + } - dev->net->netdev_ops = &ax88172_netdev_ops; - dev->net->ethtool_ops = &ax88172_ethtool_ops; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) + dev->net->do_ioctl = ax8817x_ioctl; + dev->net->set_multicast_list = ax8817x_set_multicast; + dev->net->set_mac_address = ax8817x_set_mac_addr; +#else + dev->net->netdev_ops = &ax88x72_netdev_ops; +#endif + + dev->net->ethtool_ops = &ax88772_ethtool_ops; + + /* Register suspend and resume functions */ + data->suspend = ax88772_suspend; + data->resume = ax88772_resume; + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); mii_nway_restart(&dev->mii); + ax772a_data->autoneg_start = jiffies; + ax772a_data->Event = WAIT_AUTONEG_COMPLETE; - return 0; + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + 0, 0, 0, NULL)) < 0) { + deverr(dev, "Write medium mode register: %d", ret); + goto out2; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, + AX88772A_IPG0_DEFAULT | AX88772A_IPG1_DEFAULT << 8, + AX88772A_IPG2_DEFAULT, 0, NULL)) < 0) { + deverr(dev, "Write IPG,IPG1,IPG2 failed: %d", ret); + goto out2; + } + + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + (AX_RX_CTL_START | AX_RX_CTL_AB), + 0, 0, NULL)) < 0) { + deverr(dev, "Reset RX_CTL failed: %d", ret); + goto out2; + } + + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ + if (dev->driver_info->flags & FLAG_FRAMING_AX) { + /* hard_mtu is still the default - the device does not support + jumbo eth frames */ + dev->rx_urb_size = 2048; + } + + kfree (buf); -out: + printk (version); + + return ret; +out2: + destroy_workqueue (ax772a_data->ax_work); + kfree (ax772a_data); + kfree (buf); +out1: return ret; } -static const struct ethtool_ops ax88772_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; - -static int ax88772_link_reset(struct usbnet *dev) +static void ax88772a_unbind(struct usbnet *dev, struct usb_interface *intf) { - u16 mode; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; + + if (ax772a_data) { + + flush_workqueue (ax772a_data->ax_work); + destroy_workqueue (ax772a_data->ax_work); + + /* stop MAC operation */ + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + AX_RX_CTL_STOP, 0, 0, NULL); + + /* Power down PHY */ + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD, 0, 0, NULL); + + kfree (ax772a_data); + } +} - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88772_MEDIUM_DEFAULT; +static int ax88772b_set_csums(struct usbnet *dev) +{ + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; + u16 checksum; - if (ethtool_cmd_speed(&ecmd) != SPEED_100) - mode &= ~AX_MEDIUM_PS; + if (ax772b_data->checksum & AX_RX_CHECKSUM) + checksum = AX_RXCOE_DEF_CSUM; + else + checksum = 0; - if (ecmd.duplex != DUPLEX_FULL) - mode &= ~AX_MEDIUM_FD; + ax8817x_write_cmd (dev, AX_CMD_WRITE_RXCOE_CTL, + checksum, 0, 0, NULL); - netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", - ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); + if (ax772b_data->checksum & AX_TX_CHECKSUM) + checksum = AX_TXCOE_DEF_CSUM; + else + checksum = 0; - asix_write_medium_mode(dev, mode); + ax8817x_write_cmd (dev, AX_CMD_WRITE_TXCOE_CTL, + checksum, 0, 0, NULL); return 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) +static u32 ax88772b_get_tx_csum(struct net_device *netdev) +{ + struct usbnet *dev = netdev_priv(netdev); + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; -static const struct net_device_ops ax88772_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = asix_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = asix_ioctl, - .ndo_set_multicast_list = asix_set_multicast, -}; + return (ax772b_data->checksum & AX_TX_CHECKSUM); +} -static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) +static u32 ax88772b_get_rx_csum(struct net_device *netdev) +{ + struct usbnet *dev = netdev_priv(netdev); + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; + + return (ax772b_data->checksum & AX_RX_CHECKSUM); +} + +static int ax88772b_set_rx_csum(struct net_device *netdev, u32 val) +{ + struct usbnet *dev = netdev_priv(netdev); + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; + + if (val) + ax772b_data->checksum |= AX_RX_CHECKSUM; + else + ax772b_data->checksum &= ~AX_RX_CHECKSUM; + + return ax88772b_set_csums(dev); +} + +static int ax88772b_set_tx_csum(struct net_device *netdev, u32 val) { - int ret, embd_phy; - u16 rx_ctl; - struct asix_data *data = (struct asix_data *)&dev->data; - u8 buf[ETH_ALEN]; - u32 phyid; + struct usbnet *dev = netdev_priv(netdev); + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; - data->eeprom_len = AX88772_EEPROM_LEN; + if (val) + ax772b_data->checksum |= AX_TX_CHECKSUM; + else + ax772b_data->checksum &= ~AX_TX_CHECKSUM; + + ethtool_op_set_tx_csum(netdev, val); + + return ax88772b_set_csums(dev); +} +#endif +static struct ethtool_ops ax88772b_ethtool_ops = { + .get_drvinfo = ax8817x_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = axusbnet_get_msglevel, + .set_msglevel = axusbnet_set_msglevel, + .get_wol = ax8817x_get_wol, + .set_wol = ax8817x_set_wol, + .get_eeprom_len = ax8817x_get_eeprom_len, + .get_eeprom = ax8817x_get_eeprom, + .get_settings = ax8817x_get_settings, + .set_settings = ax8817x_set_settings, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) + .set_tx_csum = ax88772b_set_tx_csum, + .get_tx_csum = ax88772b_get_tx_csum, + .get_rx_csum = ax88772b_get_rx_csum, + .set_rx_csum = ax88772b_set_rx_csum, +#endif +}; - usbnet_get_endpoints(dev,intf); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29) +static const struct net_device_ops ax88772b_netdev_ops = { + .ndo_open = axusbnet_open, + .ndo_stop = axusbnet_stop, + .ndo_start_xmit = axusbnet_start_xmit, + .ndo_tx_timeout = axusbnet_tx_timeout, + .ndo_change_mtu = axusbnet_change_mtu, + .ndo_do_ioctl = ax8817x_ioctl, + .ndo_get_stats = axusbnet_get_stats, + .ndo_set_mac_address = ax8817x_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,2,0) + .ndo_set_multicast_list = ax88772b_set_multicast, +#else + .ndo_set_rx_mode = ax88772b_set_multicast, +#endif +}; +#endif - if ((ret = asix_write_gpio(dev, - AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0) - goto out; +static int ax88772b_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int ret; + void *buf; + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + struct ax88772b_data *ax772b_data; + u16 *tmp16; + u8 i; + u8 TempPhySelect; + bool InternalPhy; + u8 default_asix_mac[ETH_ALEN] = { 0x00, 0x0e, 0xc6, 0x87, 0x72, 0x01 }; + + axusbnet_get_endpoints(dev,intf); + + buf = kmalloc (6, GFP_KERNEL); + if (!buf) { + deverr(dev, "Cannot allocate memory for buffer"); + return -ENOMEM; + } + tmp16 = (u16 *)buf; - /* 0x10 is the phy id of the embedded 10/100 ethernet phy */ - embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); - if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, - embd_phy, 0, 0, NULL)) < 0) { - dbg("Select PHY #1 failed: %d", ret); - goto out; + ax772b_data = kmalloc (sizeof(*ax772b_data), GFP_KERNEL); + if (!ax772b_data) { + deverr(dev, "Cannot allocate memory for AX88772B data"); + kfree (buf); + return -ENOMEM; + } + memset (ax772b_data, 0, sizeof(*ax772b_data)); + dev->priv = ax772b_data; + + ax772b_data->ax_work = create_singlethread_workqueue ("ax88772b"); + if (!ax772b_data->ax_work) { + kfree (buf); + kfree (ax772b_data); + return -ENOMEM; } - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0) - goto out; + ax772b_data->dev = dev; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK (&ax772b_data->check_link, ax88772b_link_reset, dev); +#else + INIT_WORK (&ax772b_data->check_link, ax88772b_link_reset); +#endif + + if ((ret = ax8817x_read_cmd (dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, + &TempPhySelect)) < 0) { + deverr(dev, "read SW interface selection status register" + "failed: %d\n", ret); + goto err_out; + } - msleep(150); - if ((ret = asix_sw_reset(dev, AX_SWRESET_CLEAR)) < 0) - goto out; + TempPhySelect &= 0x0C; - msleep(150); - if (embd_phy) { - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0) - goto out; + if (TempPhySelect == AX_PHYSEL_SSRMII) { + InternalPhy = false; + ax772b_data->OperationMode = OPERATION_MAC_MODE; + ax772b_data->PhySelect = 0x00; + } + else if (TempPhySelect == AX_PHYSEL_SSRRMII) { + InternalPhy = true; + ax772b_data->OperationMode = OPERATION_PHY_MODE; + ax772b_data->PhySelect = 0x00; + } + else if (TempPhySelect == AX_PHYSEL_SSMII) { + InternalPhy = true; + ax772b_data->OperationMode = OPERATION_MAC_MODE; + ax772b_data->PhySelect = 0x01; } else { - if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0) - goto out; + deverr(dev, "Unknown MII type\n"); + goto err_out; } - msleep(150); - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after software reset", rx_ctl); - if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0) - goto out; + /* reload eeprom data */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + AXGPIOS_RSE, 0, 0, NULL)) < 0) { + deverr(dev, "Failed to enable GPIO finction: %d", ret); + goto err_out; + } + msleep(5); - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); + /* Get the EEPROM data*/ + if ((ret = ax8817x_read_cmd (dev, AX_CMD_READ_EEPROM, + 0x18, 0, 2, (void *)tmp16)) < 0) { + deverr(dev, "read SROM address 18h failed: %d", ret); + goto err_out; + } + le16_to_cpus(tmp16); + ax772b_data->psc = *tmp16 & 0xFF00; + /* End of get EEPROM data */ + + /* Get the MAC address from EEPROM */ + memset(buf, 0, ETH_ALEN); + for (i = 0; i < (ETH_ALEN >> 1); i++) { + if ((ret = ax8817x_read_cmd (dev, AX_CMD_READ_EEPROM, + 0x04 + i, 0, 2, (buf + i * 2))) < 0) { + deverr(dev, "read SROM address 04h failed: %d", ret); + goto err_out; + } + } - /* Get the MAC address */ - if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, - 0, 0, ETH_ALEN, buf)) < 0) { - dbg("Failed to read MAC address: %d", ret); - goto out; + /* Check for default ASIX MAC (e.g. 00:0e:c6:87:72:01) in case of no EEPROM being present */ + if (!memcmp(buf, default_asix_mac, ETH_ALEN)) { + if (g_usr_mac && (g_usr_mac < 3)) { + /* Get user set MAC address */ + if (g_usr_mac == 2) { + /* 0x100000 offset for 2nd Ethernet MAC */ + g_mac_addr[3] += 0x10; + if (g_mac_addr[3] < 0x10) + devwarn(dev, "MAC address byte 3 (0x%02x) wrap around", g_mac_addr[3]); + } + memcpy(buf, g_mac_addr, ETH_ALEN); + g_usr_mac++; + } else devwarn(dev, "using default ASIX MAC"); } memcpy(dev->net->dev_addr, buf, ETH_ALEN); + /* Set the MAC address */ + if ((ret = ax8817x_write_cmd (dev, AX88772_CMD_WRITE_NODE_ID, + 0, 0, ETH_ALEN, buf)) < 0) { + deverr(dev, "set MAC address failed: %d", ret); + goto err_out; + } + /* Initialize MII structure */ dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = asix_get_phy_addr(dev); + dev->mii.mdio_read = ax8817x_mdio_read_le; + dev->mii.mdio_write = ax88772b_mdio_write_le; + dev->mii.phy_id_mask = 0xff; + dev->mii.reg_num_mask = 0xff; - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); + /* Get the PHY id */ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, + 0, 0, 2, buf)) < 0) { + deverr(dev, "Error reading PHY ID: %02x", ret); + goto err_out; + } else if (ret < 2) { + /* this should always return 2 bytes */ + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", + ret); + ret = -EIO; + goto err_out; + } - if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0) - goto out; + if (InternalPhy) + dev->mii.phy_id = *((u8 *)buf + 1); + else + dev->mii.phy_id = *((u8 *)buf); - msleep(150); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, + ax772b_data->PhySelect, 0, 0, NULL)) < 0) { + deverr(dev, "Select PHY #1 failed: %d", ret); + goto err_out; + } - if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) - goto out; +#if 0 + /* select the embedded 10/100 Ethernet PHY */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, + AX_PHYSEL_SSEN | AX_PHYSEL_PSEL | AX_PHYSEL_SSMII + , 0, 0, NULL)) < 0) { + deverr(dev, "Select PHY #1 failed: %d", ret); + goto err_out; + } - msleep(150); + if(dev->mii.phy_id != 0x10) { + deverr(dev, "Got wrong PHY ID: %02x", dev->mii.phy_id); + ret = -EIO; + goto err_out; + } +#endif + if ((ret = ax88772a_phy_powerup (dev)) < 0) + goto err_out; + + /* stop MAC operation */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + AX_RX_CTL_STOP, 0, 0, NULL)) < 0) { + deverr(dev, "Reset RX_CTL failed: %d", ret); + goto err_out; + } - dev->net->netdev_ops = &ax88772_netdev_ops; - dev->net->ethtool_ops = &ax88772_ethtool_ops; + /* make sure the driver can enable sw mii operation */ + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, + 0, 0, 0, NULL)) < 0) { + deverr(dev, "Enabling software MII failed: %d", ret); + goto err_out; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) + dev->net->do_ioctl = ax8817x_ioctl; + dev->net->set_multicast_list = ax88772b_set_multicast; + dev->net->set_mac_address = ax8817x_set_mac_addr; +#else + dev->net->netdev_ops = &ax88772b_netdev_ops; +#endif + + dev->net->ethtool_ops = &ax88772b_ethtool_ops; + + /* Register suspend and resume functions */ + data->suspend = ax88772b_suspend; + data->resume = ax88772b_resume; + + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id + , MII_BMCR, 0x3900); + + if (dev->mii.phy_id != 0x10) + ax8817x_mdio_write_le(dev->net, 0x10, MII_BMCR, 0x3900); + + + if (dev->mii.phy_id == 0x10 && ax772b_data->OperationMode + != OPERATION_PHY_MODE) { + + *tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, 0x12, + ((*tmp16 & 0xFF9F) | 0x0040)); + } + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA); mii_nway_restart(&dev->mii); - if ((ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT)) < 0) - goto out; + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + 0, 0, 0, NULL)) < 0) { + deverr(dev, "Failed to write medium mode: %d", ret); + goto err_out; + } - if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, - AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, - AX88772_IPG2_DEFAULT, 0, NULL)) < 0) { - dbg("Write IPG,IPG1,IPG2 failed: %d", ret); - goto out; + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, + AX88772A_IPG0_DEFAULT | AX88772A_IPG1_DEFAULT << 8, + AX88772A_IPG2_DEFAULT, 0, NULL)) < 0) { + deverr(dev, "Failed to write interframe gap: %d", ret); + goto err_out; } - /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0) - goto out; + dev->net->features |= NETIF_F_IP_CSUM; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) + dev->net->features |= NETIF_F_IPV6_CSUM; +#endif - rx_ctl = asix_read_rx_ctl(dev); - dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); + ax772b_data->checksum = AX_RX_CHECKSUM | AX_TX_CHECKSUM; + if ((ret = ax88772b_set_csums(dev)) < 0) { + deverr(dev, "Write RX_COE/TX_COE failed: %d", ret); + goto err_out; + } - rx_ctl = asix_read_medium_status(dev); - dbg("Medium Status is 0x%04x after all initializations", rx_ctl); + dev->rx_size = bsize & 0x07; + if (dev->udev->speed == USB_SPEED_HIGH) { - /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* hard_mtu is still the default - the device does not support - jumbo eth frames */ + if ((ret = ax8817x_write_cmd (dev, 0x2A, + AX88772B_BULKIN_SIZE[dev->rx_size].byte_cnt, + AX88772B_BULKIN_SIZE[dev->rx_size].threshold, + 0, NULL)) < 0) { + deverr(dev, "Reset RX_CTL failed: %d", ret); + goto err_out; + } + + dev->rx_urb_size = AX88772B_BULKIN_SIZE[dev->rx_size].size; + } else { + if ((ret = ax8817x_write_cmd (dev, 0x2A, + 0x8000, 0x8001, 0, NULL)) < 0) { + deverr(dev, "Reset RX_CTL failed: %d", ret); + goto err_out; + } dev->rx_urb_size = 2048; } - return 0; -out: + /* Configure RX header type */ + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_RX_CTL, + (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_HEADER_DEFAULT), + 0, 0, NULL)) < 0) { + deverr(dev, "Reset RX_CTL failed: %d", ret); + goto err_out; + } + + /* Overwrite power saving configuration from eeprom */ + if ((ret = ax8817x_write_cmd (dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | (ax772b_data->psc & 0x7FFF), 0, 0, NULL)) < 0) { + deverr(dev, "Failed to configure PHY power saving: %d", ret); + goto err_out; + } + + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) + netif_carrier_on(dev->net); + + kfree (buf); + printk (version); + + return ret; +err_out: + destroy_workqueue (ax772b_data->ax_work); + kfree (buf); + kfree (ax772b_data); return ret; } -static struct ethtool_ops ax88178_ethtool_ops = { - .get_drvinfo = asix_get_drvinfo, - .get_link = asix_get_link, - .get_msglevel = usbnet_get_msglevel, - .set_msglevel = usbnet_set_msglevel, - .get_wol = asix_get_wol, - .set_wol = asix_set_wol, - .get_eeprom_len = asix_get_eeprom_len, - .get_eeprom = asix_get_eeprom, - .get_settings = usbnet_get_settings, - .set_settings = usbnet_set_settings, - .nway_reset = usbnet_nway_reset, -}; +static void ax88772b_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; + + if (ax772b_data) { + /* Check for user set MAC address */ + if (!memcmp(dev->net->dev_addr, g_mac_addr, ETH_ALEN)) { + /* Release user set MAC address */ + g_usr_mac--; + + if (g_usr_mac == 2) { + /* 0x100000 offset for 2nd Ethernet MAC */ + g_mac_addr[3] -= 0x10; + if (g_mac_addr[3] > 0xf0) + devwarn(dev, "MAC address byte 3 (0x%02x) wrap around", g_mac_addr[3]); + } + } + + flush_workqueue (ax772b_data->ax_work); + destroy_workqueue (ax772b_data->ax_work); + + /* stop MAC operation */ + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + AX_RX_CTL_STOP, 0, 0, NULL); + + /* Power down PHY */ + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD, 0, 0, NULL); + + kfree (ax772b_data); + } +} -static int marvell_phy_init(struct usbnet *dev) +static int +ax88178_media_check (struct usbnet *dev, struct ax88178_data *ax178dataptr) { - struct asix_data *data = (struct asix_data *)&dev->data; - u16 reg; + int fullduplex; + u16 tempshort = 0; + u16 media; + u16 advertise, lpa, result, stat1000; + + advertise = ax8817x_mdio_read_le (dev->net, + dev->mii.phy_id, MII_ADVERTISE); + lpa = ax8817x_mdio_read_le (dev->net, dev->mii.phy_id, MII_LPA); + result = advertise & lpa; + + stat1000 = ax8817x_mdio_read_le (dev->net, + dev->mii.phy_id, MII_STAT1000); + + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && + (ax178dataptr->LedMode == 1)) { + tempshort = ax8817x_mdio_read_le (dev->net, + dev->mii.phy_id, MARVELL_MANUAL_LED) & 0xfc0f; + } - netdev_dbg(dev->net, "marvell_phy_init()\n"); + fullduplex=1; + if (stat1000 & LPA_1000FULL) { + media = MEDIUM_GIGA_MODE | MEDIUM_FULL_DUPLEX_MODE | + MEDIUM_ENABLE_125MHZ | MEDIUM_ENABLE_RECEIVE; + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && + (ax178dataptr->LedMode == 1)) + tempshort|= 0x3e0; + } else if (result & LPA_100FULL) { + media = MEDIUM_FULL_DUPLEX_MODE | MEDIUM_ENABLE_RECEIVE | + MEDIUM_MII_100M_MODE; + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && + (ax178dataptr->LedMode == 1)) + tempshort|= 0x3b0; + } else if (result & LPA_100HALF) { + fullduplex = 0; + media = MEDIUM_ENABLE_RECEIVE | MEDIUM_MII_100M_MODE; + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && + (ax178dataptr->LedMode == 1)) + tempshort |= 0x3b0; + } else if (result & LPA_10FULL) { + media = MEDIUM_FULL_DUPLEX_MODE | MEDIUM_ENABLE_RECEIVE; + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && + (ax178dataptr->LedMode == 1)) + tempshort |= 0x2f0; + } else { + media = MEDIUM_ENABLE_RECEIVE; + fullduplex=0; + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && + (ax178dataptr->LedMode == 1)) + tempshort |= 0x02f0; + } - reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); - netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && + (ax178dataptr->LedMode == 1)) { + ax8817x_mdio_write_le (dev->net, + dev->mii.phy_id, MARVELL_MANUAL_LED, tempshort); + } - asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, - MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); + media |= 0x0004; + if(ax178dataptr->UseRgmii) + media |= 0x0008; + if(fullduplex) { + media |= 0x0020; //ebable tx flow control as default; + media |= 0x0010; //ebable rx flow control as default; + } - if (data->ledmode) { - reg = asix_mdio_read(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL); - netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); + return media; +} - reg &= 0xf8ff; - reg |= (1 + 0x0100); - asix_mdio_write(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL, reg); +static void Vitess_8601_Init (struct usbnet *dev, int State) +{ + u16 reg; - reg = asix_mdio_read(dev->net, dev->mii.phy_id, - MII_MARVELL_LED_CTRL); - netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); - reg &= 0xfc0f; + switch (State) { + case 0: // tx, rx clock skew + ax8817x_swmii_mdio_write_le (dev->net, dev->mii.phy_id, 31, 1); + ax8817x_swmii_mdio_write_le (dev->net, dev->mii.phy_id, 28, 0); + ax8817x_swmii_mdio_write_le (dev->net, dev->mii.phy_id, 31, 0); + break; + + case 1: + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 31, 0x52B5); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, 0x009E); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0xDD39); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87AA); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0xA7B4); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, + ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 18)); + + reg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 17) & ~0x003f) | 0x003c; + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, reg); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87B4); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0xa794); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, + ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 18)); + + reg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 17) & ~0x003f) | 0x003e; + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, reg); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x8794); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, 0x00f7); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0xbe36); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x879e); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0xa7a0); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, + ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 18)); + + reg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 17) & ~0x003f) | 0x0034; + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, reg); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87a0); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, 0x003c); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0xf3cf); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87a2); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, 0x003c); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0xf3cf); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87a4); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, 0x003c); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0xd287); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87a6); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0xa7a8); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, + ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 18)); + + reg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 17) & ~0x0fff) | 0x0125; + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, reg); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87a8); + + // Enable Smart Pre-emphasis + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0xa7fa); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, + ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 18)); + + reg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 17) & ~0x0008) | 0x0008; + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, reg); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87fa); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 31, 0); + + break; } +} - return 0; +static void +marvell_88E1510_magic_init(struct usbnet *dev) +{ + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 22, 0xff); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0x214b); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x2144); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0x0c28); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x2146); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0xb233); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x214d); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, 0xcc0c); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x2159); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 22, 0x00fb); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 7, 0xc00d); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 22, 0); } -static int marvell_led_status(struct usbnet *dev, u16 speed) +static int +ax88178_phy_init (struct usbnet *dev, struct ax88178_data *ax178dataptr) { - u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); + int i; + u16 PhyAnar, PhyAuxCtrl, PhyCtrl, TempShort, PhyID1; + u16 PhyReg = 0; - netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); + //Disable MII operation of AX88178 Hardware + ax8817x_write_cmd (dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); - /* Clear out the center LED bits - 0x03F0 */ - reg &= 0xfc0f; - switch (speed) { - case SPEED_1000: - reg |= 0x03e0; - break; - case SPEED_100: - reg |= 0x03b0; - break; - default: - reg |= 0x02f0; + //Read SROM - MiiPhy Address (ID) + ax8817x_read_cmd (dev, AX_CMD_READ_PHY_ID, 0, 0, 2, &dev->mii.phy_id); + le32_to_cpus (&dev->mii.phy_id); + + /* Initialize MII structure */ + dev->mii.phy_id >>= 8; + dev->mii.phy_id &= PHY_ID_MASK; + dev->mii.dev = dev->net; + dev->mii.mdio_read = ax8817x_mdio_read_le; + dev->mii.mdio_write = ax8817x_mdio_write_le; + dev->mii.phy_id_mask = 0x3f; + dev->mii.reg_num_mask = 0x1f; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11) + dev->mii.supports_gmii = 1; +#endif + + if (ax178dataptr->PhyMode == PHY_MODE_MAC_TO_MAC_GMII) + { + ax178dataptr->UseRgmii = 0; + ax178dataptr->MediaLink = MEDIUM_GIGA_MODE | + MEDIUM_FULL_DUPLEX_MODE | + MEDIUM_ENABLE_125MHZ | + MEDIUM_ENABLE_RECEIVE | + MEDIUM_ENABLE_RX_FLOWCTRL | + MEDIUM_ENABLE_TX_FLOWCTRL; + + goto SkipPhySetting; } - netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); - asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); + // test read phy register 2 + if (!ax178dataptr->UseGpio0) { + i = 1000; + while (i--) { + PhyID1 = ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, GMII_PHY_OUI); + if ((PhyID1 == 0x000f) || (PhyID1 == 0x0141) || + (PhyID1 == 0x0282) || (PhyID1 == 0x004d) || + (PhyID1 == 0x0243) || (PhyID1 == 0x001C) || + (PhyID1 == 0x0007)) + break; + msleep(5); + } + if (i < 0) + return -EIO; + } - return 0; -} + ax178dataptr->UseRgmii = 0; + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { + PhyReg = ax8817x_swmii_mdio_read_le(dev->net, + dev->mii.phy_id, 27); + if (!(PhyReg & 4) && !(ax178dataptr->LedMode & 0x10)) { + ax178dataptr->UseRgmii = 1; + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 20, 0x82); + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + } else if (ax178dataptr->LedMode & 0x10) { + + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + marvell_88E1510_magic_init(dev); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 22, 2); + + PhyReg = ax8817x_swmii_mdio_read_le(dev->net, + dev->mii.phy_id, 21); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 21, PhyReg | 0x30); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 22, 0); + + } + } else if ((ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) || + (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0_GMII)) { + if (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) { + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + } + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V1) { + // not Cameo + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) { + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + } -static int ax88178_link_reset(struct usbnet *dev) -{ - u16 mode; - struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - struct asix_data *data = (struct asix_data *)&dev->data; - u32 speed; + for (i = 0; i < (sizeof(CICADA_FAMILY_HWINIT) / + sizeof(CICADA_FAMILY_HWINIT[0])); i++) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, + CICADA_FAMILY_HWINIT[i].offset, + CICADA_FAMILY_HWINIT[i].value); + } - netdev_dbg(dev->net, "ax88178_link_reset()\n"); + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2) { + // not Cameo + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) + { + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + } - mii_check_media(&dev->mii, 1, 1); - mii_ethtool_gset(&dev->mii, &ecmd); - mode = AX88178_MEDIUM_DEFAULT; - speed = ethtool_cmd_speed(&ecmd); + for (i = 0; i < (sizeof(CICADA_V2_HWINIT) / + sizeof(CICADA_V2_HWINIT[0])); i++) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, CICADA_V2_HWINIT[i].offset, + CICADA_V2_HWINIT[i].value); + } + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2_ASIX) { + // not Cameo + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) + { + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + } - if (speed == SPEED_1000) - mode |= AX_MEDIUM_GM; - else if (speed == SPEED_100) - mode |= AX_MEDIUM_PS; - else - mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); + for (i = 0; i < (sizeof(CICADA_V2_HWINIT) / + sizeof(CICADA_V2_HWINIT[0])); i++) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, CICADA_V2_HWINIT[i].offset, + CICADA_V2_HWINIT[i].value); + } + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211CL) { + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211BN) { + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8251CL) { + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; + } else if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) { + ax178dataptr->UseRgmii = 1; + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; +// Vitess_8601_Init (dev, 0); + } - mode |= AX_MEDIUM_ENCK; + if (ax178dataptr->PhyMode != PHY_MODE_ATTANSIC_V0) { + // software reset + ax8817x_swmii_mdio_write_le ( + dev->net, dev->mii.phy_id, GMII_PHY_CONTROL, + ax8817x_swmii_mdio_read_le ( + dev->net, dev->mii.phy_id, GMII_PHY_CONTROL) + | GMII_CONTROL_RESET); + msleep (1); + } - if (ecmd.duplex == DUPLEX_FULL) - mode |= AX_MEDIUM_FD; - else - mode &= ~AX_MEDIUM_FD; + if ((ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) || + (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0_GMII)) { + if (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) + { + i = 1000; + while (i--) + { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 21, 0x1001); + + PhyReg = ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 21); + if ((PhyReg & 0xf00f) == 0x1001) + break; + } + if (i < 0) + return -EIO; + } + + if (ax178dataptr->LedMode == 4) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 28, 0x7417); + } else if (ax178dataptr->LedMode == 9) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 28, 0x7a10); + } else if (ax178dataptr->LedMode == 10) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 28, 0x7a13); + } + + for (i = 0; i < (sizeof(AGERE_FAMILY_HWINIT) / + sizeof(AGERE_FAMILY_HWINIT[0])); i++) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, AGERE_FAMILY_HWINIT[i].offset, + AGERE_FAMILY_HWINIT[i].value); + } + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211CL) { + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 0x1f, 0x0005); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 0x0c, 0); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 0x01, + (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 0x01) | 0x0080)); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 0x1f, 0); + + if (ax178dataptr->LedMode == 12) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 0x1f, 0x0002); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 0x1a, 0x00cb); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 0x1f, 0); + } + } else if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) { + Vitess_8601_Init (dev, 1); + } + + // read phy register 0 + PhyCtrl = ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, GMII_PHY_CONTROL); + TempShort = PhyCtrl; + PhyCtrl &= ~(GMII_CONTROL_POWER_DOWN | GMII_CONTROL_ISOLATE); + if (PhyCtrl != TempShort) { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, GMII_PHY_CONTROL, PhyCtrl); + } + + // led + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { + if (ax178dataptr->LedMode == 1) { + + PhyReg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 24) & 0xf8ff) | (1 + 0x100); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 24, PhyReg); + PhyReg = ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 25) & 0xfc0f; + + } else if (ax178dataptr->LedMode == 2) { + + PhyReg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 24) & 0xf886) | + (1 + 0x10 + 0x300); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 24, PhyReg); + + } else if (ax178dataptr->LedMode == 5) { + + PhyReg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 24) & 0xf8be) | + (1 + 0x40 + 0x300); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 24, PhyReg); + + } else if (ax178dataptr->LedMode == 7) { + + PhyReg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 24) & 0xf8ff) | + (1 + 0x100); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 24, PhyReg); + + } else if (ax178dataptr->LedMode == 8) { + + PhyReg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 24) & 0xf8be) | + (1 + 0x40 + 0x100); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 24, PhyReg); + + } else if (ax178dataptr->LedMode == 11) { + + PhyReg = ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 24) & 0x4106; + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 24, PhyReg); + + } else if (ax178dataptr->LedMode == 0x10) { + //MARVEL 88e1510 use default led setting + } + + } else if ((ax178dataptr->PhyMode == PHY_MODE_CICADA_V1) || + (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2) || + (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2_ASIX)) { + + if (ax178dataptr->LedMode == 3) { + + PhyReg = (ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 27) & 0xFCFF) | 0x0100; + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 27, PhyReg); + } + + } + + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) + { + if (ax178dataptr->LedMode == 1) + PhyReg |= 0x3f0; + } + + PhyAnar = 1 | (GMII_ANAR_PAUSE | GMII_ANAR_100TXFD | GMII_ANAR_100TX | + GMII_ANAR_10TFD | GMII_ANAR_10T | GMII_ANAR_ASYM_PAUSE); + + PhyAuxCtrl = GMII_1000_AUX_CTRL_FD_CAPABLE; + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, GMII_PHY_ANAR, PhyAnar); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, GMII_PHY_1000BT_CONTROL, PhyAuxCtrl); + + if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) + { + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 31, 0x52B5); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0xA7F8); + + TempShort = ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 17) & (~0x0018); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 17, TempShort); + + TempShort = ax8817x_swmii_mdio_read_le (dev->net, + dev->mii.phy_id, 18); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 18, TempShort); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 16, 0x87F8); + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 31, 0); + } + + if (ax178dataptr->PhyMode == PHY_MODE_ATTANSIC_V0) { + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, GMII_PHY_CONTROL, 0x9000); + + } else { + PhyCtrl &= ~GMII_CONTROL_LOOPBACK; + PhyCtrl |= (GMII_CONTROL_ENABLE_AUTO | GMII_CONTROL_START_AUTO); + + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, GMII_PHY_CONTROL, PhyCtrl); + } + + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { + if (ax178dataptr->LedMode == 1) + ax8817x_swmii_mdio_write_le (dev->net, + dev->mii.phy_id, 25, PhyReg); + } - netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", - speed, ecmd.duplex, mode); +SkipPhySetting: - asix_write_medium_mode(dev, mode); + ax8817x_write_cmd (dev, AX_CMD_WRITE_MEDIUM_MODE, + ax178dataptr->MediaLink, 0, 0, NULL); - if (data->phymode == PHY_MODE_MARVELL && data->ledmode) - marvell_led_status(dev, speed); + ax8817x_write_cmd (dev, AX_CMD_WRITE_IPG0, + AX88772_IPG0_DEFAULT | (AX88772_IPG1_DEFAULT << 8), + AX88772_IPG2_DEFAULT, 0, NULL); + + msleep (1); + + ax8817x_write_cmd (dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); return 0; } -static void ax88178_set_mfb(struct usbnet *dev) +static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) { - u16 mfb = AX_RX_CTL_MFB_16384; - u16 rxctl; - u16 medium; - int old_rx_urb_size = dev->rx_urb_size; + int ret; + void *buf; + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + struct ax88178_data *ax178dataptr = NULL; - if (dev->hard_mtu < 2048) { - dev->rx_urb_size = 2048; - mfb = AX_RX_CTL_MFB_2048; - } else if (dev->hard_mtu < 4096) { - dev->rx_urb_size = 4096; - mfb = AX_RX_CTL_MFB_4096; - } else if (dev->hard_mtu < 8192) { - dev->rx_urb_size = 8192; - mfb = AX_RX_CTL_MFB_8192; - } else if (dev->hard_mtu < 16384) { + axusbnet_get_endpoints(dev,intf); + + buf = kmalloc(6, GFP_KERNEL); + if(!buf) { + deverr(dev, "Cannot allocate memory for buffer"); + return -ENOMEM; + } + + /* allocate 178 data */ + ax178dataptr = kmalloc (sizeof (*ax178dataptr), GFP_KERNEL); + if (!ax178dataptr) { + deverr(dev, "Cannot allocate memory for AX88178 data"); + ret = -ENOMEM; + goto error_out; + } + memset (ax178dataptr, 0, sizeof (struct ax88178_data)); + dev->priv = ax178dataptr; + /* end of allocate 178 data */ + + /* Get the EEPROM data*/ + if ((ret = ax8817x_read_cmd (dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, + (void *)(&ax178dataptr->EepromData))) < 0) { + deverr(dev, "read SROM address 17h failed: %d", ret); + goto error_out; + } + le16_to_cpus (&ax178dataptr->EepromData); + /* End of get EEPROM data */ + + if (ax178dataptr->EepromData == 0xffff) { + ax178dataptr->PhyMode = PHY_MODE_MARVELL; + ax178dataptr->LedMode = 0; + ax178dataptr->UseGpio0 = 1; //True + } else { + ax178dataptr->PhyMode = (u8)(ax178dataptr->EepromData & + EEPROMMASK); + ax178dataptr->LedMode = (u8)(ax178dataptr->EepromData >> 8); + if (ax178dataptr->LedMode == 6) // for buffalo new (use gpio2) + ax178dataptr->LedMode = 1; + else if (ax178dataptr->LedMode == 1) + ax178dataptr->BuffaloOld = 1; + + + if(ax178dataptr->EepromData & 0x80) { + ax178dataptr->UseGpio0=0; //MARVEL se and other + } else { + ax178dataptr->UseGpio0=1; //cameo + } + } + + if (ax178dataptr->UseGpio0) { + + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + AXGPIOS_GPO0EN | AXGPIOS_RSE, + 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (25); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO2 | AXGPIOS_GPO2EN | + AXGPIOS_GPO0EN), 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (15); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + AXGPIOS_GPO2EN | AXGPIOS_GPO0EN, + 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (245); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO2 | AXGPIOS_GPO2EN | + AXGPIOS_GPO0EN), 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + } else { // vitesse + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_RSE | AXGPIOS_GPO0EN | + AXGPIOS_GPO0), 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (25); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), + 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (25); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | + AXGPIOS_GPO2EN), 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (245); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), + 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + } + } else { // use gpio1 + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO1 |AXGPIOS_GPO1EN | AXGPIOS_RSE), + 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + if (ax178dataptr->BuffaloOld) { + + msleep (350); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + AXGPIOS_GPO1EN, 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (350); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + AXGPIOS_GPO1EN | AXGPIOS_GPO1, + 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + } + else + { + msleep (25); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), + 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (25); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | + AXGPIOS_GPO2EN), 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + + msleep (245); + + if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS, + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), + 0, 0, NULL)) < 0) { + deverr(dev, "write GPIO failed: %d", ret); + goto error_out; + } + } + } + + if ((ret = ax8817x_write_cmd(dev, + AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL)) < 0) { + deverr(dev, "Select PHY failed: %d", ret); + goto error_out; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD | AX_SWRESET_PRL, 0, 0, NULL)) < 0) { + deverr(dev, "Issue sw reset failed: %d", ret); + goto error_out; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + 0, 0, 0, NULL)) < 0) { + deverr(dev, "Issue rx ctrl failed: %d", ret); + goto error_out; + } + + /* Get the MAC address */ + memset(buf, 0, ETH_ALEN); + if ((ret = ax8817x_read_cmd (dev, AX88772_CMD_READ_NODE_ID, + 0, 0, ETH_ALEN, buf)) < 0) { + deverr(dev, "read AX_CMD_READ_NODE_ID failed: %d", ret); + goto error_out; + } + memcpy(dev->net->dev_addr, buf, ETH_ALEN); + /* End of get MAC address */ + + if ((ret = ax88178_phy_init (dev, ax178dataptr)) < 0) + goto error_out; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) + dev->net->do_ioctl = ax8817x_ioctl; + dev->net->set_multicast_list = ax88178_set_multicast; + dev->net->set_mac_address = ax88178_set_mac_addr; +#else + dev->net->netdev_ops = &ax88178_netdev_ops; +#endif + dev->net->ethtool_ops = &ax8817x_ethtool_ops; + + /* Register suspend and resume functions */ + data->suspend = ax88772_suspend; + data->resume = ax88772_resume; + + if (dev->driver_info->flags & FLAG_FRAMING_AX) { dev->rx_urb_size = 16384; - mfb = AX_RX_CTL_MFB_16384; } - rxctl = asix_read_rx_ctl(dev); - asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + (AX_RX_CTL_MFB | AX_RX_CTL_START | AX_RX_CTL_AB), + 0, 0, NULL)) < 0) { + deverr(dev, "write RX ctrl reg failed: %d", ret); + goto error_out; + } - medium = asix_read_medium_status(dev); - if (dev->net->mtu > 1500) - medium |= AX_MEDIUM_JFE; - else - medium &= ~AX_MEDIUM_JFE; - asix_write_medium_mode(dev, medium); + kfree (buf); + printk (version); + return ret; - if (dev->rx_urb_size > old_rx_urb_size) - usbnet_unlink_rx_urbs(dev); +error_out: + if (ax178dataptr) + kfree (ax178dataptr); + kfree (buf); + return ret; } -static int ax88178_change_mtu(struct net_device *net, int new_mtu) +static void ax88178_unbind(struct usbnet *dev, struct usb_interface *intf) { - struct usbnet *dev = netdev_priv(net); - int ll_mtu = new_mtu + net->hard_header_len + 4; + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; - netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); + if (ax178dataptr) { - if (new_mtu <= 0 || ll_mtu > 16384) - return -EINVAL; + /* stop MAC operation */ + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, + AX_RX_CTL_STOP, 0, 0, NULL); + + kfree (ax178dataptr); + } +} + +static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + u8 *head; + u32 header; + char *packet; + struct sk_buff *ax_skb; + u16 size; + + head = (u8 *) skb->data; + memcpy(&header, head, sizeof(header)); + le32_to_cpus(&header); + packet = head + sizeof(header); - if ((ll_mtu % dev->maxpacket) == 0) - return -EDOM; + skb_pull(skb, 4); - net->mtu = new_mtu; - dev->hard_mtu = net->mtu + net->hard_header_len; - ax88178_set_mfb(dev); + while (skb->len > 0) { + if ((short)(header & 0x0000ffff) != + ~((short)((header & 0xffff0000) >> 16))) { + deverr(dev, "header length data is error 0x%08x, %d\n", + header, skb->len); + } + /* get the packet length */ + size = (u16) (header & 0x0000ffff); - return 0; + if ((skb->len) - ((size + 1) & 0xfffe) == 0) { + + /* Make sure ip header is aligned on 32-bit boundary */ + if (!((unsigned long)skb->data & 0x02)) { + memmove (skb->data - 2, skb->data, size); + skb->data -= 2; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + skb->tail = skb->data + size; +#else + skb_set_tail_pointer (skb, size); +#endif + } + skb->truesize = size + sizeof(struct sk_buff); + return 2; + } + + if (size > ETH_FRAME_LEN) { + deverr(dev, "invalid rx length %d", size); + return 0; + } + ax_skb = skb_clone(skb, GFP_ATOMIC); + if (ax_skb) { + + /* Make sure ip header is aligned on 32-bit boundary */ + if (!((unsigned long)packet & 0x02)) { + memmove (packet - 2, packet, size); + packet -= 2; + } + ax_skb->data = packet; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + ax_skb->tail = packet + size; +#else + skb_set_tail_pointer (ax_skb, size); +#endif + ax_skb->truesize = size + sizeof(struct sk_buff); + axusbnet_skb_return(dev, ax_skb); + + } else { + return 0; + } + + skb_pull(skb, (size + 1) & 0xfffe); + + if (skb->len == 0) + break; + + head = (u8 *) skb->data; + memcpy(&header, head, sizeof(header)); + le32_to_cpus(&header); + packet = head + sizeof(header); + skb_pull(skb, 4); + } + + if (skb->len < 0) { + deverr(dev, "invalid rx length %d", skb->len); + return 0; + } + return 1; } -static const struct net_device_ops ax88178_netdev_ops = { - .ndo_open = usbnet_open, - .ndo_stop = usbnet_stop, - .ndo_start_xmit = usbnet_start_xmit, - .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_set_mac_address = asix_set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = asix_set_multicast, - .ndo_do_ioctl = asix_ioctl, - .ndo_change_mtu = ax88178_change_mtu, -}; +static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) +{ + int padlen = ((skb->len + 4) % 512) ? 0 : 4; + u32 packet_len; + u32 padbytes = 0xffff0000; -static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) +#if (!AX_FORCE_BUFF_ALIGN) + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + + if ((!skb_cloned(skb)) + && ((headroom + tailroom) >= (4 + padlen))) { + if ((headroom < 4) || (tailroom < padlen)) { + skb->data = memmove(skb->head + 4, skb->data, skb->len); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + skb->tail = skb->data + skb->len; +#else + skb_set_tail_pointer (skb, skb->len); +#endif + } + } else +#endif + { + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, 4, padlen, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + skb_push(skb, 4); + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); + cpu_to_le32s(&packet_len); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + memcpy(skb->data, &packet_len, sizeof(packet_len)); +#else + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); +#endif + + if ((skb->len % 512) == 0) { + cpu_to_le32s(&padbytes); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + memcpy(skb->tail, &padbytes, sizeof(padbytes)); +#else + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); +#endif + skb_put(skb, sizeof(padbytes)); + } + return skb; +} + +static void +ax88772b_rx_checksum (struct sk_buff *skb, struct ax88772b_rx_header *rx_hdr) { - struct asix_data *data = (struct asix_data *)&dev->data; - int ret; - u8 buf[ETH_ALEN]; - __le16 eeprom; - u8 status; - int gpio0 = 0; - u32 phyid; + skb->ip_summed = CHECKSUM_NONE; + + /* checksum error bit is set */ + if (rx_hdr->l3_csum_err || rx_hdr->l4_csum_err) { + return; + } + + /* It must be a TCP or UDP packet with a valid checksum */ + if ((rx_hdr->l4_type == AX_RXHDR_L4_TYPE_TCP) || + (rx_hdr->l4_type == AX_RXHDR_L4_TYPE_UDP)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } +} + +static int ax88772b_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct ax88772b_rx_header rx_hdr; + struct sk_buff *ax_skb; + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; - usbnet_get_endpoints(dev,intf); + while (skb->len > 0) { - asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); - dbg("GPIO Status: 0x%04x", status); + le16_to_cpus((u16 *)skb->data); + le16_to_cpus(((u16 *)skb->data) + 1); - asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); - asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); - asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); + memcpy (&rx_hdr, skb->data, sizeof (struct ax88772b_rx_header)); - dbg("EEPROM index 0x17 is 0x%04x", eeprom); + if ((short)rx_hdr.len != (~((short)rx_hdr.len_bar) & 0x7FF)) { + return 0; + } - if (eeprom == cpu_to_le16(0xffff)) { - data->phymode = PHY_MODE_MARVELL; - data->ledmode = 0; - gpio0 = 1; - } else { - data->phymode = le16_to_cpu(eeprom) & 7; - data->ledmode = le16_to_cpu(eeprom) >> 8; - gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; + if (rx_hdr.len > (ETH_FRAME_LEN + 4)) { + deverr(dev, "invalid rx length %d", rx_hdr.len); + return 0; + } + + if (skb->len - ((rx_hdr.len + + sizeof (struct ax88772b_rx_header) + 3) & + 0xfffc) == 0) { + skb_pull(skb, sizeof (struct ax88772b_rx_header)); + skb->len = rx_hdr.len; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + skb->tail = skb->data + rx_hdr.len; +#else + skb_set_tail_pointer(skb, rx_hdr.len); +#endif + skb->truesize = rx_hdr.len + sizeof(struct sk_buff); + + if (ax772b_data->checksum & AX_RX_CHECKSUM) + ax88772b_rx_checksum (skb, &rx_hdr); + + return 2; + } + + ax_skb = skb_clone(skb, GFP_ATOMIC); + if (ax_skb) { + ax_skb->len = rx_hdr.len; + ax_skb->data = skb->data + + sizeof (struct ax88772b_rx_header); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + ax_skb->tail = ax_skb->data + rx_hdr.len; +#else + skb_set_tail_pointer(ax_skb, rx_hdr.len); +#endif + ax_skb->truesize = rx_hdr.len + sizeof(struct sk_buff); + + if (ax772b_data->checksum & AX_RX_CHECKSUM) { + ax88772b_rx_checksum (ax_skb, &rx_hdr); + } + + axusbnet_skb_return(dev, ax_skb); + + } else { + return 0; + } + + skb_pull(skb, ((rx_hdr.len + + sizeof (struct ax88772b_rx_header) + 3) + & 0xfffc)); } - dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); - asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); - if ((le16_to_cpu(eeprom) >> 8) != 1) { - asix_write_gpio(dev, 0x003c, 30); - asix_write_gpio(dev, 0x001c, 300); - asix_write_gpio(dev, 0x003c, 30); - } else { - dbg("gpio phymode == 1 path"); - asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); - asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); + if (skb->len < 0) { + deverr(dev, "invalid rx length %d", skb->len); + return 0; } + return 1; +} - asix_sw_reset(dev, 0); - msleep(150); +static struct sk_buff * +ax88772b_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) +{ + int padlen = ((skb->len + 4) % 512) ? 0 : 4; + u32 packet_len; + u32 padbytes = 0xffff0000; - asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); - msleep(150); +#if (!AX_FORCE_BUFF_ALIGN) + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); - asix_write_rx_ctl(dev, 0); + if ((!skb_cloned(skb)) + && ((headroom + tailroom) >= (4 + padlen))) { + if ((headroom < 4) || (tailroom < padlen)) { + skb->data = memmove(skb->head + 4, skb->data, skb->len); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + skb->tail = skb->data + skb->len; +#else + skb_set_tail_pointer(skb, skb->len); +#endif + } + } else +#endif + { + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, 4, padlen, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } - /* Get the MAC address */ - if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, - 0, 0, ETH_ALEN, buf)) < 0) { - dbg("Failed to read MAC address: %d", ret); - goto out; + skb_push(skb, 4); + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); + + cpu_to_le32s (&packet_len); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + memcpy(skb->data, &packet_len, sizeof(packet_len)); +#else + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); +#endif + + if ((skb->len % 512) == 0) { + cpu_to_le32s (&padbytes); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + memcpy(skb->tail, &padbytes, sizeof(padbytes)); +#else + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); +#endif + skb_put(skb, sizeof(padbytes)); } - memcpy(dev->net->dev_addr, buf, ETH_ALEN); - /* Initialize MII structure */ - dev->mii.dev = dev->net; - dev->mii.mdio_read = asix_mdio_read; - dev->mii.mdio_write = asix_mdio_write; - dev->mii.phy_id_mask = 0x1f; - dev->mii.reg_num_mask = 0xff; - dev->mii.supports_gmii = 1; - dev->mii.phy_id = asix_get_phy_addr(dev); + return skb; +} - dev->net->netdev_ops = &ax88178_netdev_ops; - dev->net->ethtool_ops = &ax88178_ethtool_ops; +static const u8 ChkCntSel [6][3] = +{ + {12, 23, 31}, + {12, 31, 23}, + {23, 31, 12}, + {23, 12, 31}, + {31, 12, 23}, + {31, 23, 12} +}; - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void ax88772_link_reset (void *data) +{ + struct usbnet *dev = (struct usbnet *)data; + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; +#else +static void ax88772_link_reset (struct work_struct *work) +{ + struct ax88772_data *ax772_data = container_of (work, + struct ax88772_data, check_link); + struct usbnet *dev = ax772_data->dev; +#endif + + if (ax772_data->Event == AX_SET_RX_CFG) { + u16 bmcr; + u16 mode; + + ax772_data->Event = AX_NOP; + + mode = AX88772_MEDIUM_DEFAULT; + + bmcr = ax8817x_mdio_read_le(dev->net, + dev->mii.phy_id, MII_BMCR); + if (!(bmcr & BMCR_FULLDPLX)) + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; + if (!(bmcr & BMCR_SPEED100)) + mode &= ~AX88772_MEDIUM_100MB; + + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + mode, 0, 0, NULL); + return; + } + + switch (ax772_data->Event) { + case WAIT_AUTONEG_COMPLETE: + if (jiffies > (ax772_data->autoneg_start + 5 * HZ)) { + ax772_data->Event = PHY_POWER_DOWN; + ax772_data->TickToExpire = 23; + } + break; + case PHY_POWER_DOWN: + if (ax772_data->TickToExpire == 23) { + /* Set Phy Power Down */ + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD, + 0, 0, NULL); + --ax772_data->TickToExpire; + } else if (--ax772_data->TickToExpire == 0) { + /* Set Phy Power Up */ + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL, 0, 0, NULL); + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD | AX_SWRESET_IPRL, 0, 0, NULL); + msleep(10); + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL, 0, 0, NULL); + msleep(60); + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_CLEAR, 0, 0, NULL); + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL, 0, 0, NULL); + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, + MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | + ADVERTISE_PAUSE_CAP); + mii_nway_restart(&dev->mii); + + ax772_data->Event = PHY_POWER_UP; + ax772_data->TickToExpire = 47; + } + break; + case PHY_POWER_UP: + if (--ax772_data->TickToExpire == 0) { + ax772_data->Event = PHY_POWER_DOWN; + ax772_data->TickToExpire = 23; + } + break; + default: + break; + } + return; +} - if (data->phymode == PHY_MODE_MARVELL) { - marvell_phy_init(dev); - msleep(60); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void ax88772a_link_reset (void *data) +{ + struct usbnet *dev = (struct usbnet *)data; + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; +#else +static void ax88772a_link_reset (struct work_struct *work) +{ + struct ax88772a_data *ax772a_data = container_of (work, + struct ax88772a_data, check_link); + struct usbnet *dev = ax772a_data->dev; +#endif + int PowSave = (ax772a_data->EepromData >> 14); + u16 phy_reg; + + if (ax772a_data->Event == AX_SET_RX_CFG) { + u16 bmcr; + u16 mode; + + ax772a_data->Event = AX_NOP; + + mode = AX88772_MEDIUM_DEFAULT; + + bmcr = ax8817x_mdio_read_le(dev->net, + dev->mii.phy_id, MII_BMCR); + if (!(bmcr & BMCR_FULLDPLX)) + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; + if (!(bmcr & BMCR_SPEED100)) + mode &= ~AX88772_MEDIUM_100MB; + + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + mode, 0, 0, NULL); + return; } - asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, - BMCR_RESET | BMCR_ANENABLE); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, + switch (ax772a_data->Event) { + case WAIT_AUTONEG_COMPLETE: + if (jiffies > (ax772a_data->autoneg_start + 5 * HZ)) { + ax772a_data->Event = CHK_CABLE_EXIST; + ax772a_data->TickToExpire = 14; + } + break; + case CHK_CABLE_EXIST: + phy_reg = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); + if ((phy_reg != 0x8012) && (phy_reg != 0x8013)) { + ax8817x_mdio_write_le(dev->net, + dev->mii.phy_id, 0x16, 0x4040); + mii_nway_restart(&dev->mii); + ax772a_data->Event = CHK_CABLE_STATUS; + ax772a_data->TickToExpire = 31; + } else if (--ax772a_data->TickToExpire == 0) { + mii_nway_restart(&dev->mii); + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; + if (PowSave == 0x03){ + ax772a_data->TickToExpire = 47; + } else if (PowSave == 0x01) { + ax772a_data->DlyIndex = (u8)(jiffies % 6); + ax772a_data->DlySel = 0; + ax772a_data->TickToExpire = + ChkCntSel[ax772a_data->DlyIndex][ax772a_data->DlySel]; + } + } + break; + case CHK_CABLE_EXIST_AGAIN: + /* if cable disconnected */ + phy_reg = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); + if ((phy_reg != 0x8012) && (phy_reg != 0x8013)) { + mii_nway_restart(&dev->mii); + ax772a_data->Event = CHK_CABLE_STATUS; + ax772a_data->TickToExpire = 31; + } else if (--ax772a_data->TickToExpire == 0) { + /* Power down PHY */ + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, + AX_SWRESET_IPPD, + 0, 0, NULL); + ax772a_data->Event = PHY_POWER_DOWN; + if (PowSave == 0x03){ + ax772a_data->TickToExpire = 23; + } else if (PowSave == 0x01) { + ax772a_data->TickToExpire = 31; + } + } + break; + case PHY_POWER_DOWN: + if (--ax772a_data->TickToExpire == 0) { + ax772a_data->Event = PHY_POWER_UP; + } + break; + case CHK_CABLE_STATUS: + if (--ax772a_data->TickToExpire == 0) { + ax8817x_mdio_write_le(dev->net, + dev->mii.phy_id, 0x16, 0x4040); + mii_nway_restart(&dev->mii); + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; + if (PowSave == 0x03){ + ax772a_data->TickToExpire = 47; + } else if (PowSave == 0x01) { + ax772a_data->DlyIndex = (u8)(jiffies % 6); + ax772a_data->DlySel = 0; + ax772a_data->TickToExpire = + ChkCntSel[ax772a_data->DlyIndex][ax772a_data->DlySel]; + } + } + break; + case PHY_POWER_UP: + + ax88772a_phy_powerup (dev); + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, - ADVERTISE_1000FULL); - mii_nway_restart(&dev->mii); + mii_nway_restart(&dev->mii); + + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; + + if (PowSave == 0x03){ + ax772a_data->TickToExpire = 47; + + } else if (PowSave == 0x01) { + + if (++ax772a_data->DlySel >= 3) { + ax772a_data->DlyIndex = (u8)(jiffies % 6); + ax772a_data->DlySel = 0; + } + ax772a_data->TickToExpire = + ChkCntSel[ax772a_data->DlyIndex][ax772a_data->DlySel]; + } + break; + default: + break; + } - if ((ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT)) < 0) - goto out; + return; +} - if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0) - goto out; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void ax88772b_link_reset (void *data) +{ + struct usbnet *dev = (struct usbnet *)data; + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; +#else +static void ax88772b_link_reset (struct work_struct *work) +{ + struct ax88772b_data *ax772b_data = container_of (work, + struct ax88772b_data, check_link); + struct usbnet *dev = ax772b_data->dev; +#endif + + switch (ax772b_data->Event) { + + case AX_SET_RX_CFG: + { + u16 bmcr = ax8817x_mdio_read_le(dev->net, + dev->mii.phy_id, MII_BMCR); + u16 mode = AX88772_MEDIUM_DEFAULT; + + if (!(bmcr & BMCR_FULLDPLX)) + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; + if (!(bmcr & BMCR_SPEED100)) + mode &= ~AX88772_MEDIUM_100MB; + + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + mode, 0, 0, NULL); + break; + } + case PHY_POWER_UP: + { + u16 tmp16; - /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ - if (dev->driver_info->flags & FLAG_FRAMING_AX) { - /* hard_mtu is still the default - the device does not support - jumbo eth frames */ - dev->rx_urb_size = 2048; + ax88772a_phy_powerup (dev); + tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, 0x12, + ((tmp16 & 0xFF9F) | 0x0040)); + + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + break; + } + case AX_CHK_AUTODETACH: + { + u16 tmp16; + int ret; + void *buf; + buf = kmalloc(6, GFP_KERNEL); + devwarn(dev, "EVENT: AX_CHK_AUTODETACH\n"); + /* Get the EEPROM data*/ + if ((ret = ax8817x_read_cmd (dev, AX_CMD_READ_EEPROM, + 0x18, 0, 2, (void *)(&tmp16))) < 0) { + deverr(dev, "read SROM address 18h failed: %d", ret); + } + else { + ax772b_data->psc = le16_to_cpu(tmp16) & 0xFF00; + devwarn(dev, "EEPROM (0x18) = : %04X", ax772b_data->psc); + if ((ret = ax8817x_write_cmd (dev, AX_CMD_SW_RESET, + AX_SWRESET_IPRL | (ax772b_data->psc & 0x7FFF), 0, 0, buf)) < 0) { + deverr(dev, "Failed to configure PHY power saving: %d", ret); + } + } + break; + } + default: + break; } + + ax772b_data->Event = AX_NOP; + + return; +} + +static int ax88178_set_media(struct usbnet *dev) +{ + int ret; + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; + int media; + + media = ax88178_media_check (dev, ax178dataptr); + if (media < 0) + return media; + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + media, 0, 0, NULL)) < 0) { + deverr(dev, "write mode medium reg failed: %d", ret); + return ret; + } + return 0; +} -out: - return ret; +static int ax88178_link_reset(struct usbnet *dev) +{ + return ax88178_set_media (dev); +} + +static int ax_suspend (struct usb_interface *intf, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) + pm_message_t message) +#else + u32 message) +#endif +{ + struct usbnet *dev = usb_get_intfdata(intf); + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + + return data->suspend (intf, message); +} + +static int ax_resume (struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + + return data->resume (intf); } +static const struct driver_info ax88178_info = { + .description = "ASIX AX88178 USB 2.0 Ethernet", + .bind = ax88178_bind, + .unbind = ax88178_unbind, + .status = ax88178_status, + .link_reset = ax88178_link_reset, + .reset = ax88178_link_reset, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88772_rx_fixup, + .tx_fixup = ax88772_tx_fixup, +}; + +static const struct driver_info belkin178_info = { + .description = "Belkin Gigabit USB 2.0 Network Adapter", + .bind = ax88178_bind, + .unbind = ax88178_unbind, + .status = ax8817x_status, + .link_reset = ax88178_link_reset, + .reset = ax88178_link_reset, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88772_rx_fixup, + .tx_fixup = ax88772_tx_fixup, +}; + static const struct driver_info ax8817x_info = { .description = "ASIX AX8817x USB 2.0 Ethernet", - .bind = ax88172_bind, - .status = asix_status, + .bind = ax8817x_bind, + .status = ax8817x_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x00130103, + .flags = FLAG_ETHER, }; static const struct driver_info dlink_dub_e100_info = { .description = "DLink DUB-E100 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, + .bind = ax8817x_bind, + .status = ax8817x_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x009f9d9f, + .flags = FLAG_ETHER, }; static const struct driver_info netgear_fa120_info = { .description = "Netgear FA-120 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, + .bind = ax8817x_bind, + .status = ax8817x_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x00130103, + .flags = FLAG_ETHER, }; static const struct driver_info hawking_uf200_info = { .description = "Hawking UF200 USB Ethernet", - .bind = ax88172_bind, - .status = asix_status, + .bind = ax8817x_bind, + .status = ax8817x_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, - .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x001f1d1f, + .flags = FLAG_ETHER, }; static const struct driver_info ax88772_info = { .description = "ASIX AX88772 USB 2.0 Ethernet", .bind = ax88772_bind, - .status = asix_status, - .link_reset = ax88772_link_reset, - .reset = ax88772_link_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, + .unbind = ax88772_unbind, + .status = ax88772_status, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88772_rx_fixup, + .tx_fixup = ax88772_tx_fixup, + .stop = ax88772b_stop, + .reset = ax88772b_reset, }; -static const struct driver_info ax88178_info = { - .description = "ASIX AX88178 USB 2.0 Ethernet", - .bind = ax88178_bind, - .status = asix_status, - .link_reset = ax88178_link_reset, - .reset = ax88178_link_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, +static const struct driver_info dlink_dub_e100b_info = { + .description = "D-Link DUB-E100 USB 2.0 Fast Ethernet Adapter", + .bind = ax88772_bind, + .unbind = ax88772_unbind, + .status = ax88772_status, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88772_rx_fixup, + .tx_fixup = ax88772_tx_fixup, + .stop = ax88772b_stop, + .reset = ax88772b_reset, +}; + +static const struct driver_info ax88772a_info = { + .description = "ASIX AX88772A USB 2.0 Ethernet", + .bind = ax88772a_bind, + .unbind = ax88772a_unbind, + .status = ax88772a_status, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88772_rx_fixup, + .tx_fixup = ax88772_tx_fixup, + .stop = ax88772b_stop, + .reset = ax88772b_reset, +}; + +static const struct driver_info ax88772b_info = { + .description = "ASIX AX88772B USB 2.0 Ethernet", + .bind = ax88772b_bind, + .unbind = ax88772b_unbind, + .status = ax88772b_status, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, + .rx_fixup = ax88772b_rx_fixup, + .tx_fixup = ax88772b_tx_fixup, + .stop = ax88772b_stop, + .reset = ax88772b_reset, }; static const struct usb_device_id products [] = { { + // 88178 + USB_DEVICE (0x0b95, 0x1780), + .driver_info = (unsigned long) &ax88178_info, +}, { + // 88178 for billianton linksys + USB_DEVICE (0x077b, 0x2226), + .driver_info = (unsigned long) &ax88178_info, +}, { + // ABOCOM for linksys + USB_DEVICE (0x1737, 0x0039), + .driver_info = (unsigned long) &ax88178_info, +}, { + // ABOCOM for pci + USB_DEVICE (0x14ea, 0xab11), + .driver_info = (unsigned long) &ax88178_info, +}, { + // Belkin + USB_DEVICE (0x050d, 0x5055), + .driver_info = (unsigned long) &belkin178_info, +}, { // Linksys USB200M USB_DEVICE (0x077b, 0x2226), .driver_info = (unsigned long) &ax8817x_info, @@ -1457,6 +3677,14 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x2001, 0x1a00), .driver_info = (unsigned long) &dlink_dub_e100_info, }, { + // DLink DUB-E100B + USB_DEVICE (0x2001, 0x3c05), + .driver_info = (unsigned long) &dlink_dub_e100b_info, +}, { + // DLink DUB-E100B + USB_DEVICE (0x07d1, 0x3c05), + .driver_info = (unsigned long) &dlink_dub_e100b_info, +}, { // Intellinet, ST Lab USB Ethernet USB_DEVICE (0x0b95, 0x1720), .driver_info = (unsigned long) &ax8817x_info, @@ -1465,9 +3693,9 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x07b8, 0x420a), .driver_info = (unsigned long) &hawking_uf200_info, }, { - // Billionton Systems, USB2AR - USB_DEVICE (0x08dd, 0x90ff), - .driver_info = (unsigned long) &ax8817x_info, + // Billionton Systems, USB2AR + USB_DEVICE (0x08dd, 0x90ff), + .driver_info = (unsigned long) &ax8817x_info, }, { // ATEN UC210T USB_DEVICE (0x0557, 0x2009), @@ -1477,10 +3705,6 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x0411, 0x003d), .driver_info = (unsigned long) &ax8817x_info, }, { - // Buffalo LUA-U2-GT 10/100/1000 - USB_DEVICE (0x0411, 0x006e), - .driver_info = (unsigned long) &ax88178_info, -}, { // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" USB_DEVICE (0x6189, 0x182d), .driver_info = (unsigned long) &ax8817x_info, @@ -1497,86 +3721,53 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x1631, 0x6200), .driver_info = (unsigned long) &ax8817x_info, }, { - // JVC MP-PRX1 Port Replicator - USB_DEVICE (0x04f1, 0x3008), - .driver_info = (unsigned long) &ax8817x_info, -}, { - // ASIX AX88772B 10/100 - USB_DEVICE (0x0b95, 0x772b), - .driver_info = (unsigned long) &ax88772_info, -}, { // ASIX AX88772 10/100 - USB_DEVICE (0x0b95, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, { - // ASIX AX88178 10/100/1000 - USB_DEVICE (0x0b95, 0x1780), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Logitec LAN-GTJ/U2A - USB_DEVICE (0x0789, 0x0160), - .driver_info = (unsigned long) &ax88178_info, -}, { - // Linksys USB200M Rev 2 - USB_DEVICE (0x13b1, 0x0018), - .driver_info = (unsigned long) &ax88772_info, + USB_DEVICE (0x0b95, 0x7720), + .driver_info = (unsigned long) &ax88772_info, }, { - // 0Q0 cable ethernet - USB_DEVICE (0x1557, 0x7720), - .driver_info = (unsigned long) &ax88772_info, -}, { - // DLink DUB-E100 H/W Ver B1 - USB_DEVICE (0x07d1, 0x3c05), - .driver_info = (unsigned long) &ax88772_info, -}, { - // DLink DUB-E100 H/W Ver B1 Alternate - USB_DEVICE (0x2001, 0x3c05), - .driver_info = (unsigned long) &ax88772_info, -}, { - // Linksys USB1000 - USB_DEVICE (0x1737, 0x0039), - .driver_info = (unsigned long) &ax88178_info, + // ASIX AX88772 10/100 + USB_DEVICE (0x125E, 0x180D), + .driver_info = (unsigned long) &ax88772_info, }, { - // IO-DATA ETG-US2 - USB_DEVICE (0x04bb, 0x0930), - .driver_info = (unsigned long) &ax88178_info, + // ASIX AX88772A 10/100 + USB_DEVICE (0x0b95, 0x772A), + .driver_info = (unsigned long) &ax88772a_info, }, { - // Belkin F5D5055 - USB_DEVICE(0x050d, 0x5055), - .driver_info = (unsigned long) &ax88178_info, + // ASIX AX88772A 10/100 + USB_DEVICE (0x0db0, 0xA877), + .driver_info = (unsigned long) &ax88772a_info, }, { - // Apple USB Ethernet Adapter - USB_DEVICE(0x05ac, 0x1402), - .driver_info = (unsigned long) &ax88772_info, + // ASIX AX88772A 10/100 + USB_DEVICE (0x0421, 0x772A), + .driver_info = (unsigned long) &ax88772a_info, }, { - // Cables-to-Go USB Ethernet Adapter - USB_DEVICE(0x0b95, 0x772a), - .driver_info = (unsigned long) &ax88772_info, + // Linksys 200M + USB_DEVICE (0x13B1, 0x0018), + .driver_info = (unsigned long) &ax88772a_info, }, { - // ABOCOM for pci - USB_DEVICE(0x14ea, 0xab11), - .driver_info = (unsigned long) &ax88178_info, + USB_DEVICE (0x05ac, 0x1402), + .driver_info = (unsigned long) &ax88772a_info, }, { - // ASIX 88772a - USB_DEVICE(0x0db0, 0xa877), - .driver_info = (unsigned long) &ax88772_info, + // ASIX AX88772B 10/100 + USB_DEVICE (0x0b95, 0x772B), + .driver_info = (unsigned long) &ax88772b_info, }, { - // Asus USB Ethernet Adapter - USB_DEVICE (0x0b95, 0x7e2b), - .driver_info = (unsigned long) &ax88772_info, + // ASIX AX88772B 10/100 + USB_DEVICE (0x0b95, 0x7E2B), + .driver_info = (unsigned long) &ax88772b_info, }, { }, // END }; MODULE_DEVICE_TABLE(usb, products); static struct usb_driver asix_driver = { +// .owner = THIS_MODULE, .name = "asix", .id_table = products, - .probe = usbnet_probe, - .suspend = usbnet_suspend, - .resume = usbnet_resume, - .disconnect = usbnet_disconnect, - .supports_autosuspend = 1, + .probe = axusbnet_probe, + .suspend = ax_suspend, + .resume = ax_resume, + .disconnect = axusbnet_disconnect, }; static int __init asix_init(void) diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h new file mode 100644 index 000000000000..ea51eb7001e2 --- /dev/null +++ b/drivers/net/usb/asix.h @@ -0,0 +1,558 @@ +#ifndef __LINUX_USBNET_ASIX_H +#define __LINUX_USBNET_ASIX_H + +/* + * Turn on this flag if the implementation of your USB host controller + * cannot handle non-double word aligned buffer. + * When turn on this flag, driver will fixup egress packet aligned on double + * word boundary before deliver to USB host controller. And will Disable the + * function "skb_reserve (skb, NET_IP_ALIGN)" to retain the buffer aligned on + * double word alignment for ingress packets. + */ +#define AX_FORCE_BUFF_ALIGN 0 + +#define AX_MONITOR_MODE 0x01 +#define AX_MONITOR_LINK 0x02 +#define AX_MONITOR_MAGIC 0x04 +#define AX_MONITOR_HSFS 0x10 + +/* AX88172 Medium Status Register values */ +#define AX_MEDIUM_FULL_DUPLEX 0x02 +#define AX_MEDIUM_TX_ABORT_ALLOW 0x04 +#define AX_MEDIUM_FLOW_CONTROL_EN 0x10 +#define AX_MCAST_FILTER_SIZE 8 +#define AX_MAX_MCAST 64 + +#define AX_EEPROM_LEN 0x40 + +#define AX_SWRESET_CLEAR 0x00 +#define AX_SWRESET_RR 0x01 +#define AX_SWRESET_RT 0x02 +#define AX_SWRESET_PRTE 0x04 +#define AX_SWRESET_PRL 0x08 +#define AX_SWRESET_BZ 0x10 +#define AX_SWRESET_IPRL 0x20 +#define AX_SWRESET_IPPD 0x40 +#define AX_SWRESET_IPOSC 0x0080 +#define AX_SWRESET_IPPSL_0 0x0100 +#define AX_SWRESET_IPPSL_1 0x0200 +#define AX_SWRESET_IPCOPS 0x0400 +#define AX_SWRESET_IPCOPSC 0x0800 +#define AX_SWRESET_AUTODETACH 0x1000 +#define AX_SWRESET_WOLLP 0x8000 + +#define AX88772_IPG0_DEFAULT 0x15 +#define AX88772_IPG1_DEFAULT 0x0c +#define AX88772_IPG2_DEFAULT 0x0E + +#define AX88772A_IPG0_DEFAULT 0x15 +#define AX88772A_IPG1_DEFAULT 0x16 +#define AX88772A_IPG2_DEFAULT 0x1A + +#define AX88772_MEDIUM_FULL_DUPLEX 0x0002 +#define AX88772_MEDIUM_RESERVED 0x0004 +#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010 +#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020 +#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080 +#define AX88772_MEDIUM_RX_ENABLE 0x0100 +#define AX88772_MEDIUM_100MB 0x0200 +#define AX88772_MEDIUM_DEFAULT \ + (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \ + AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \ + AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE ) + +#define AX_CMD_SET_SW_MII 0x06 +#define AX_CMD_READ_MII_REG 0x07 +#define AX_CMD_WRITE_MII_REG 0x08 +#define AX_CMD_SET_HW_MII 0x0a +#define AX_CMD_READ_EEPROM 0x0b +#define AX_CMD_WRITE_EEPROM 0x0c +#define AX_CMD_WRITE_EEPROM_EN 0x0d +#define AX_CMD_WRITE_EEPROM_DIS 0x0e +#define AX_CMD_WRITE_RX_CTL 0x10 +#define AX_CMD_READ_IPG012 0x11 +#define AX_CMD_WRITE_IPG0 0x12 +#define AX_CMD_WRITE_IPG1 0x13 +#define AX_CMD_WRITE_IPG2 0x14 +#define AX_CMD_WRITE_MULTI_FILTER 0x16 +#define AX_CMD_READ_NODE_ID 0x17 +#define AX_CMD_READ_PHY_ID 0x19 +#define AX_CMD_READ_MEDIUM_MODE 0x1a +#define AX_CMD_WRITE_MEDIUM_MODE 0x1b +#define AX_CMD_READ_MONITOR_MODE 0x1c +#define AX_CMD_WRITE_MONITOR_MODE 0x1d +#define AX_CMD_WRITE_GPIOS 0x1f +#define AX_CMD_SW_RESET 0x20 +#define AX_CMD_SW_PHY_STATUS 0x21 +#define AX_CMD_SW_PHY_SELECT 0x22 + #define AX_PHYSEL_PSEL (1 << 0) + #define AX_PHYSEL_ASEL (1 << 1) + #define AX_PHYSEL_SSMII (0 << 2) + #define AX_PHYSEL_SSRMII (1 << 2) + #define AX_PHYSEL_SSRRMII (3 << 2) + #define AX_PHYSEL_SSEN (1 << 4) +#define AX88772_CMD_READ_NODE_ID 0x13 +#define AX88772_CMD_WRITE_NODE_ID 0x14 +#define AX_CMD_READ_RXCOE_CTL 0x2b +#define AX_CMD_WRITE_RXCOE_CTL 0x2c +#define AX_CMD_READ_TXCOE_CTL 0x2d +#define AX_CMD_WRITE_TXCOE_CTL 0x2e + +#define REG_LENGTH 2 +#define PHY_ID_MASK 0x1f + +#define AX_RXCOE_IPCE 0x0001 +#define AX_RXCOE_IPVE 0x0002 +#define AX_RXCOE_V6VE 0x0004 +#define AX_RXCOE_TCPE 0x0008 +#define AX_RXCOE_UDPE 0x0010 +#define AX_RXCOE_ICMP 0x0020 +#define AX_RXCOE_IGMP 0x0040 +#define AX_RXCOE_ICV6 0x0080 +#define AX_RXCOE_TCPV6 0x0100 +#define AX_RXCOE_UDPV6 0x0200 +#define AX_RXCOE_ICMV6 0x0400 +#define AX_RXCOE_IGMV6 0x0800 +#define AX_RXCOE_ICV6V6 0x1000 +#define AX_RXCOE_FOPC 0x8000 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) +#define AX_RXCOE_DEF_CSUM (AX_RXCOE_IPCE | AX_RXCOE_IPVE | \ + AX_RXCOE_V6VE | AX_RXCOE_TCPE | \ + AX_RXCOE_UDPE | AX_RXCOE_ICV6 | \ + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6) +#else +#define AX_RXCOE_DEF_CSUM (AX_RXCOE_IPCE | AX_RXCOE_IPVE | \ + AX_RXCOE_TCPE | AX_RXCOE_UDPE) +#endif + +#define AX_RXCOE_64TE 0x0100 +#define AX_RXCOE_PPPOE 0x0200 +#define AX_RXCOE_RPCE 0x8000 + +#define AX_TXCOE_IP 0x0001 +#define AX_TXCOE_TCP 0x0002 +#define AX_TXCOE_UDP 0x0004 +#define AX_TXCOE_ICMP 0x0008 +#define AX_TXCOE_IGMP 0x0010 +#define AX_TXCOE_ICV6 0x0020 + +#define AX_TXCOE_TCPV6 0x0100 +#define AX_TXCOE_UDPV6 0x0200 +#define AX_TXCOE_ICMV6 0x0400 +#define AX_TXCOE_IGMV6 0x0800 +#define AX_TXCOE_ICV6V6 0x1000 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) +#define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP | \ + AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6) +#else +#define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP) +#endif + +#define AX_TXCOE_64TE 0x0001 +#define AX_TXCOE_PPPE 0x0002 + +#define AX88772B_MAX_BULKIN_2K 0 +#define AX88772B_MAX_BULKIN_4K 1 +#define AX88772B_MAX_BULKIN_6K 2 +#define AX88772B_MAX_BULKIN_8K 3 +#define AX88772B_MAX_BULKIN_16K 4 +#define AX88772B_MAX_BULKIN_20K 5 +#define AX88772B_MAX_BULKIN_24K 6 +#define AX88772B_MAX_BULKIN_32K 7 +struct {unsigned short size, byte_cnt,threshold;} AX88772B_BULKIN_SIZE[] = +{ + /* 2k */ + {2048, 0x8000, 0x8001}, + /* 4k */ + {4096, 0x8100, 0x8147}, + /* 6k */ + {6144, 0x8200, 0x81EB}, + /* 8k */ + {8192, 0x8300, 0x83D7}, + /* 16 */ + {16384, 0x8400, 0x851E}, + /* 20k */ + {20480, 0x8500, 0x8666}, + /* 24k */ + {24576, 0x8600, 0x87AE}, + /* 32k */ + {32768, 0x8700, 0x8A3D}, +}; + + +#define AX_RX_CTL_RH1M 0x0100 /* Enable RX-Header mode 0 */ +#define AX_RX_CTL_RH2M 0x0200 /* Enable IP header in receive buffer aligned on 32-bit aligment */ +#define AX_RX_CTL_RH3M 0x0400 /* checksum value in rx header 3 */ +#define AX_RX_HEADER_DEFAULT (AX_RX_CTL_RH1M | AX_RX_CTL_RH2M) + +#define AX_RX_CTL_MFB 0x0300 /* Maximum Frame size 16384bytes */ +#define AX_RX_CTL_START 0x0080 /* Ethernet MAC start */ +#define AX_RX_CTL_AP 0x0020 /* Accept physcial address from Multicast array */ +#define AX_RX_CTL_AM 0x0010 +#define AX_RX_CTL_AB 0x0008 /* Accetp Brocadcast frames*/ +#define AX_RX_CTL_SEP 0x0004 /* Save error packets */ +#define AX_RX_CTL_AMALL 0x0002 /* Accetp all multicast frames */ +#define AX_RX_CTL_PRO 0x0001 /* Promiscuous Mode */ +#define AX_RX_CTL_STOP 0x0000 /* Stop MAC */ + +#define AX_MONITOR_MODE 0x01 +#define AX_MONITOR_LINK 0x02 +#define AX_MONITOR_MAGIC 0x04 +#define AX_MONITOR_HSFS 0x10 + +#define AX_MCAST_FILTER_SIZE 8 +#define AX_MAX_MCAST 64 +#define AX_INTERRUPT_BUFSIZE 8 + +#define AX_EEPROM_LEN 0x40 +#define AX_EEPROM_MAGIC 0xdeadbeef +#define EEPROMMASK 0x7f + +/* GPIO REGISTER */ +#define AXGPIOS_GPO0EN 0X01 // 1 << 0 +#define AXGPIOS_GPO0 0X02 // 1 << 1 +#define AXGPIOS_GPO1EN 0X04 // 1 << 2 +#define AXGPIOS_GPO1 0X08 // 1 << 3 +#define AXGPIOS_GPO2EN 0X10 // 1 << 4 +#define AXGPIOS_GPO2 0X20 // 1 << 5 +#define AXGPIOS_RSE 0X80 // 1 << 7 + +/* TX-header format */ +#define AX_TX_HDR_CPHI 0x4000 +#define AX_TX_HDR_DICF 0x8000 + +// GMII register definitions +#define GMII_PHY_CONTROL 0x00 // control reg +#define GMII_PHY_STATUS 0x01 // status reg +#define GMII_PHY_OUI 0x02 // most of the OUI bits +#define GMII_PHY_MODEL 0x03 // model/rev bits, and rest of OUI +#define GMII_PHY_ANAR 0x04 // AN advertisement reg +#define GMII_PHY_ANLPAR 0x05 // AN Link Partner +#define GMII_PHY_ANER 0x06 // AN expansion reg +#define GMII_PHY_1000BT_CONTROL 0x09 // control reg for 1000BT +#define GMII_PHY_1000BT_STATUS 0x0A // status reg for 1000BT + +// Bit definitions: GMII Control +#define GMII_CONTROL_RESET 0x8000 // reset bit in control reg +#define GMII_CONTROL_LOOPBACK 0x4000 // loopback bit in control reg +#define GMII_CONTROL_10MB 0x0000 // 10 Mbit +#define GMII_CONTROL_100MB 0x2000 // 100Mbit +#define GMII_CONTROL_1000MB 0x0040 // 1000Mbit +#define GMII_CONTROL_SPEED_BITS 0x2040 // speed bit mask +#define GMII_CONTROL_ENABLE_AUTO 0x1000 // autonegotiate enable +#define GMII_CONTROL_POWER_DOWN 0x0800 +#define GMII_CONTROL_ISOLATE 0x0400 // islolate bit +#define GMII_CONTROL_START_AUTO 0x0200 // restart autonegotiate +#define GMII_CONTROL_FULL_DUPLEX 0x0100 + +// Bit definitions: GMII Status +#define GMII_STATUS_100MB_MASK 0xE000 // any of these indicate 100 Mbit +#define GMII_STATUS_10MB_MASK 0x1800 // either of these indicate 10 Mbit +#define GMII_STATUS_AUTO_DONE 0x0020 // auto negotiation complete +#define GMII_STATUS_AUTO 0x0008 // auto negotiation is available +#define GMII_STATUS_LINK_UP 0x0004 // link status bit +#define GMII_STATUS_EXTENDED 0x0001 // extended regs exist +#define GMII_STATUS_100T4 0x8000 // capable of 100BT4 +#define GMII_STATUS_100TXFD 0x4000 // capable of 100BTX full duplex +#define GMII_STATUS_100TX 0x2000 // capable of 100BTX +#define GMII_STATUS_10TFD 0x1000 // capable of 10BT full duplex +#define GMII_STATUS_10T 0x0800 // capable of 10BT + +// Bit definitions: Auto-Negotiation Advertisement +#define GMII_ANAR_ASYM_PAUSE 0x0800 // support asymetric pause +#define GMII_ANAR_PAUSE 0x0400 // support pause packets +#define GMII_ANAR_100T4 0x0200 // support 100BT4 +#define GMII_ANAR_100TXFD 0x0100 // support 100BTX full duplex +#define GMII_ANAR_100TX 0x0080 // support 100BTX half duplex +#define GMII_ANAR_10TFD 0x0040 // support 10BT full duplex +#define GMII_ANAR_10T 0x0020 // support 10BT half duplex +#define GMII_SELECTOR_FIELD 0x001F // selector field. + +// Bit definitions: Auto-Negotiation Link Partner Ability +#define GMII_ANLPAR_100T4 0x0200 // support 100BT4 +#define GMII_ANLPAR_100TXFD 0x0100 // support 100BTX full duplex +#define GMII_ANLPAR_100TX 0x0080 // support 100BTX half duplex +#define GMII_ANLPAR_10TFD 0x0040 // support 10BT full duplex +#define GMII_ANLPAR_10T 0x0020 // support 10BT half duplex +#define GMII_ANLPAR_PAUSE 0x0400 // support pause packets +#define GMII_ANLPAR_ASYM_PAUSE 0x0800 // support asymetric pause +#define GMII_ANLPAR_ACK 0x4000 // means LCB was successfully rx'd +#define GMII_SELECTOR_8023 0x0001; + +// Bit definitions: 1000BaseT AUX Control +#define GMII_1000_AUX_CTRL_MASTER_SLAVE 0x1000 +#define GMII_1000_AUX_CTRL_FD_CAPABLE 0x0200 // full duplex capable +#define GMII_1000_AUX_CTRL_HD_CAPABLE 0x0100 // half duplex capable + +// Bit definitions: 1000BaseT AUX Status +#define GMII_1000_AUX_STATUS_FD_CAPABLE 0x0800 // full duplex capable +#define GMII_1000_AUX_STATUS_HD_CAPABLE 0x0400 // half duplex capable + +// Cicada MII Registers +#define GMII_AUX_CTRL_STATUS 0x1C +#define GMII_AUX_ANEG_CPLT 0x8000 +#define GMII_AUX_FDX 0x0020 +#define GMII_AUX_SPEED_1000 0x0010 +#define GMII_AUX_SPEED_100 0x0008 + +#ifndef ADVERTISE_PAUSE_CAP +#define ADVERTISE_PAUSE_CAP 0x0400 +#endif + +#ifndef MII_STAT1000 +#define MII_STAT1000 0x000A +#endif + +#ifndef LPA_1000FULL +#define LPA_1000FULL 0x0800 +#endif + +// medium mode register +#define MEDIUM_GIGA_MODE 0x0001 +#define MEDIUM_FULL_DUPLEX_MODE 0x0002 +#define MEDIUM_TX_ABORT_MODE 0x0004 +#define MEDIUM_ENABLE_125MHZ 0x0008 +#define MEDIUM_ENABLE_RX_FLOWCTRL 0x0010 +#define MEDIUM_ENABLE_TX_FLOWCTRL 0x0020 +#define MEDIUM_ENABLE_JUMBO_FRAME 0x0040 +#define MEDIUM_CHECK_PAUSE_FRAME_MODE 0x0080 +#define MEDIUM_ENABLE_RECEIVE 0x0100 +#define MEDIUM_MII_100M_MODE 0x0200 +#define MEDIUM_ENABLE_JAM_PATTERN 0x0400 +#define MEDIUM_ENABLE_STOP_BACKPRESSURE 0x0800 +#define MEDIUM_ENABLE_SUPPER_MAC_SUPPORT 0x1000 + +/* PHY mode */ +#define PHY_MODE_MARVELL 0 +#define PHY_MODE_CICADA_FAMILY 1 +#define PHY_MODE_CICADA_V1 1 +#define PHY_MODE_AGERE_FAMILY 2 +#define PHY_MODE_AGERE_V0 2 +#define PHY_MODE_CICADA_V2 5 +#define PHY_MODE_AGERE_V0_GMII 6 +#define PHY_MODE_CICADA_V2_ASIX 9 +#define PHY_MODE_VSC8601 10 +#define PHY_MODE_RTL8211CL 12 +#define PHY_MODE_RTL8211BN 13 +#define PHY_MODE_RTL8251CL 14 +#define PHY_MODE_ATTANSIC_V0 0x40 +#define PHY_MODE_ATTANSIC_FAMILY 0x40 +#define PHY_MODE_MAC_TO_MAC_GMII 0x7C + +/* */ +#define LED_MODE_MARVELL 0 +#define LED_MODE_CAMEO 1 + +#define MARVELL_LED_CTRL 0x18 +#define MARVELL_MANUAL_LED 0x19 + +#define PHY_IDENTIFIER 0x0002 +#define PHY_AGERE_IDENTIFIER 0x0282 +#define PHY_CICADA_IDENTIFIER 0x000f +#define PHY_MARVELL_IDENTIFIER 0x0141 + +#define PHY_MARVELL_STATUS 0x001b +#define MARVELL_STATUS_HWCFG 0x0004 /* SGMII without clock */ + +#define PHY_MARVELL_CTRL 0x0014 +#define MARVELL_CTRL_RXDELAY 0x0080 +#define MARVELL_CTRL_TXDELAY 0x0002 + +#define PHY_CICADA_EXTPAGE 0x001f +#define CICADA_EXTPAGE_EN 0x0001 +#define CICADA_EXTPAGE_DIS 0x0000 + + +struct {unsigned short value, offset; } CICADA_FAMILY_HWINIT[] = +{ + {0x0001, 0x001f}, {0x1c25, 0x0017}, {0x2a30, 0x001f}, {0x234c, 0x0010}, + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0xa7fa, 0x0000}, + {0x0012, 0x0002}, {0x3002, 0x0001}, {0x87fa, 0x0000}, {0x52b5, 0x001f}, + {0xafac, 0x0000}, {0x000d, 0x0002}, {0x001c, 0x0001}, {0x8fac, 0x0000}, + {0x2a30, 0x001f}, {0x0012, 0x0008}, {0x2a30, 0x001f}, {0x0400, 0x0014}, + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0xa760, 0x0000}, + {0x0000, 0x0002}, {0xfaff, 0x0001}, {0x8760, 0x0000}, {0x52b5, 0x001f}, + {0xa760, 0x0000}, {0x0000, 0x0002}, {0xfaff, 0x0001}, {0x8760, 0x0000}, + {0x52b5, 0x001f}, {0xafae, 0x0000}, {0x0004, 0x0002}, {0x0671, 0x0001}, + {0x8fae, 0x0000}, {0x2a30, 0x001f}, {0x0012, 0x0008}, {0x0000, 0x001f}, +}; + +struct {unsigned short value, offset; } CICADA_V2_HWINIT[] = +{ + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0x000f, 0x0002}, + {0x472a, 0x0001}, {0x8fa4, 0x0000}, {0x2a30, 0x001f}, {0x0212, 0x0008}, + {0x0000, 0x001f}, +}; + +struct {unsigned short value, offset; } CICADA_V2_ASIX_HWINIT[] = +{ + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0x0012, 0x0002}, + {0x3002, 0x0001}, {0x87fa, 0x0000}, {0x52b5, 0x001f}, {0x000f, 0x0002}, + {0x472a, 0x0001}, {0x8fa4, 0x0000}, {0x2a30, 0x001f}, {0x0212, 0x0008}, + {0x0000, 0x001f}, +}; + +struct {unsigned short value, offset; } AGERE_FAMILY_HWINIT[] = +{ + {0x0800, 0x0000}, {0x0007, 0x0012}, {0x8805, 0x0010}, {0xb03e, 0x0011}, + {0x8808, 0x0010}, {0xe110, 0x0011}, {0x8806, 0x0010}, {0xb03e, 0x0011}, + {0x8807, 0x0010}, {0xff00, 0x0011}, {0x880e, 0x0010}, {0xb4d3, 0x0011}, + {0x880f, 0x0010}, {0xb4d3, 0x0011}, {0x8810, 0x0010}, {0xb4d3, 0x0011}, + {0x8817, 0x0010}, {0x1c00, 0x0011}, {0x300d, 0x0010}, {0x0001, 0x0011}, + {0x0002, 0x0012}, +}; + +struct ax88178_data { + u16 EepromData; + u16 MediaLink; + int UseGpio0; + int UseRgmii; + u8 PhyMode; + u8 LedMode; + u8 BuffaloOld; +}; + +enum watchdog_state { + AX_NOP = 0, + CHK_LINK, /* Routine A */ + CHK_CABLE_EXIST, /* Called by A */ + CHK_CABLE_EXIST_AGAIN, /* Routine B */ + PHY_POWER_UP, /* Called by B */ + PHY_POWER_UP_BH, + PHY_POWER_DOWN, + CHK_CABLE_STATUS, /* Routine C */ + WAIT_AUTONEG_COMPLETE, + AX_SET_RX_CFG, + AX_CHK_AUTODETACH, +}; + +struct ax88772b_data { + struct usbnet *dev; + struct workqueue_struct *ax_work; + struct work_struct check_link; + unsigned long time_to_chk; + u16 psc; + u8 pw_enabled; + u8 Event; + u8 checksum; + u8 PhySelect:1; + u8 OperationMode:1; + +}; + +// define for MAC or PHY mode +#define OPERATION_MAC_MODE 0 +#define OPERATION_PHY_MODE 1 + +struct ax88772a_data { + struct usbnet *dev; + struct workqueue_struct *ax_work; + struct work_struct check_link; + unsigned long autoneg_start; +#define AX88772B_WATCHDOG (6 * HZ) + u8 Event; + u8 TickToExpire; + u8 DlyIndex; + u8 DlySel; + u16 EepromData; +}; + +struct ax88772_data { + struct usbnet *dev; + struct workqueue_struct *ax_work; + struct work_struct check_link; + unsigned long autoneg_start; + u8 Event; + u8 TickToExpire; +}; + +#define AX_RX_CHECKSUM 1 +#define AX_TX_CHECKSUM 2 + +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ +struct ax8817x_data { + u8 multi_filter[AX_MCAST_FILTER_SIZE]; + int (*resume) (struct usb_interface *intf); + int (*suspend) (struct usb_interface *intf, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) + pm_message_t message); +#else + u32 message); +#endif +}; + +struct ax88172_int_data { + u16 res1; +#define AX_INT_PPLS_LINK (1 << 0) +#define AX_INT_SPLS_LINK (1 << 1) +#define AX_INT_CABOFF_UNPLUG (1 << 7) + u8 link; + u16 res2; + u8 status; + u16 res3; +} __attribute__ ((packed)); + +#define AX_RXHDR_L4_ERR (1 << 8) +#define AX_RXHDR_L3_ERR (1 << 9) + +#define AX_RXHDR_L4_TYPE_UDP 1 +#define AX_RXHDR_L4_TYPE_ICMP 2 +#define AX_RXHDR_L4_TYPE_IGMP 3 +#define AX_RXHDR_L4_TYPE_TCP 4 +#define AX_RXHDR_L4_TYPE_TCMPV6 5 +#define AX_RXHDR_L4_TYPE_MASK 7 + +#define AX_RXHDR_L3_TYPE_IP 1 +#define AX_RXHDR_L3_TYPE_IPV6 2 + +struct ax88772b_rx_header { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u16 len:11, + res1:1, + crc:1, + mii:1, + runt:1, + mc_bc:1; + + u16 len_bar:11, + res2:5; + + u8 vlan_ind:3, + vlan_tag_striped:1, + pri:3, + res3:1; + + u8 l4_csum_err:1, + l3_csum_err:1, + l4_type:3, + l3_type:2, + ce:1; +#elif defined (__BIG_ENDIAN_BITFIELD) + u16 mc_bc:1, + runt:1, + mii:1, + crc:1, + res1:1, + len:11; + + u16 res2:5, + len_bar:11; + + u8 res3:1, + pri:3, + vlan_tag_striped:1, + vlan_ind:3; + + u8 ce:1, + l3_type:2, + l4_type:3, + l3_csum_err:1, + l4_csum_err:1; +#else +#error "Please fix <asm/byteorder.h>" +#endif + +} __attribute__ ((packed)); + +#endif /* __LINUX_USBNET_ASIX_H */ + diff --git a/drivers/net/usb/axusbnet.c b/drivers/net/usb/axusbnet.c new file mode 100644 index 000000000000..00393d38a379 --- /dev/null +++ b/drivers/net/usb/axusbnet.c @@ -0,0 +1,1374 @@ +/* + * USB Network driver infrastructure + * Copyright (C) 2000-2005 by David Brownell + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * This is a generic "USB networking" framework that works with several + * kinds of full and high speed networking devices: host-to-host cables, + * smart usb peripherals, and actual Ethernet adapters. + * + * These devices usually differ in terms of control protocols (if they + * even have one!) and sometimes they define new framing to wrap or batch + * Ethernet packets. Otherwise, they talk to USB pretty much the same, + * so interface (un)binding, endpoint I/O queues, fault handling, and other + * issues can usefully be addressed by this framework. + */ + +#define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ctype.h> +#include <linux/ethtool.h> +#include <linux/workqueue.h> +#include <linux/mii.h> +#include <linux/usb.h> +/*#include <linux/usb/usbnet.h>*/ + +#include "asix.h" +#include "axusbnet.h" + +#define DRIVER_VERSION "22-Aug-2005" + +static void axusbnet_unlink_rx_urbs(struct usbnet *); + +extern void +ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data); + +/*-------------------------------------------------------------------------*/ + +/* + * Nineteen USB 1.1 max size bulk transactions per frame (ms), max. + * Several dozen bytes of IPv4 data can fit in two such transactions. + * One maximum size Ethernet packet takes twenty four of them. + * For high speed, each frame comfortably fits almost 36 max size + * Ethernet packets (so queues should be bigger). + * + * REVISIT qlens should be members of 'struct usbnet'; the goal is to + * let the USB host controller be busy for 5msec or more before an irq + * is required, under load. Jumbograms change the equation. + */ +#define RX_MAX_QUEUE_MEMORY (60 * 1518) +#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ + (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4) +#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ + (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4) + +// reawaken network queue this soon after stopping; else watchdog barks +//#define TX_TIMEOUT_JIFFIES (5*HZ) +#define TX_TIMEOUT_JIFFIES (30*HZ) + +// throttle rx/tx briefly after some faults, so khubd might disconnect() +// us (it polls at HZ/4 usually) before we report too many false errors. +#define THROTTLE_JIFFIES (HZ/8) + +// between wakeups +#define UNLINK_TIMEOUT_MS 3 + +/*-------------------------------------------------------------------------*/ + +static const char driver_name [] = "axusbnet"; + +/* use ethtool to change the level for any given device */ +static int msg_level = -1; +module_param (msg_level, int, 0); +MODULE_PARM_DESC (msg_level, "Override default message level"); + +/*-------------------------------------------------------------------------*/ + +/* handles CDC Ethernet and many other network "bulk data" interfaces */ +static +int axusbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) +{ + int tmp; + struct usb_host_interface *alt = NULL; + struct usb_host_endpoint *in = NULL, *out = NULL; + struct usb_host_endpoint *status = NULL; + + for (tmp = 0; tmp < intf->num_altsetting; tmp++) { + unsigned ep; + + in = out = status = NULL; + alt = intf->altsetting + tmp; + + /* take the first altsetting with in-bulk + out-bulk; + * remember any status endpoint, just in case; + * ignore other endpoints and altsetttings. + */ + for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { + struct usb_host_endpoint *e; + int intr = 0; + + e = alt->endpoint + ep; + switch (e->desc.bmAttributes) { + case USB_ENDPOINT_XFER_INT: + if (!(e->desc.bEndpointAddress & USB_DIR_IN)) + continue; + intr = 1; + /* FALLTHROUGH */ + case USB_ENDPOINT_XFER_BULK: + break; + default: + continue; + } + if (e->desc.bEndpointAddress & USB_DIR_IN) { + if (!intr && !in) + in = e; + else if (intr && !status) + status = e; + } else { + if (!out) + out = e; + } + } + if (in && out) + break; + } + if (!alt || !in || !out) + return -EINVAL; + + if (alt->desc.bAlternateSetting != 0 + || !(dev->driver_info->flags & FLAG_NO_SETINT)) { + tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (tmp < 0) + return tmp; + } + + dev->in = usb_rcvbulkpipe (dev->udev, + in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + dev->out = usb_sndbulkpipe (dev->udev, + out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + dev->status = status; + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +static void intr_complete (struct urb *urb, struct pt_regs *regs); +#else +static void intr_complete (struct urb *urb); +#endif + +static int init_status (struct usbnet *dev, struct usb_interface *intf) +{ + char *buf = NULL; + unsigned pipe = 0; + unsigned maxp; + unsigned period; + + if (!dev->driver_info->status) + return 0; + + pipe = usb_rcvintpipe (dev->udev, + dev->status->desc.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK); + maxp = usb_maxpacket (dev->udev, pipe, 0); + + /* avoid 1 msec chatter: min 8 msec poll rate */ + period = max ((int) dev->status->desc.bInterval, + (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); + + buf = kmalloc (maxp, GFP_KERNEL); + if (buf) { + dev->interrupt = usb_alloc_urb (0, GFP_KERNEL); + if (!dev->interrupt) { + kfree (buf); + return -ENOMEM; + } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) + dev->interrupt->transfer_flags |= URB_ASYNC_UNLINK; +#endif + usb_fill_int_urb(dev->interrupt, dev->udev, pipe, + buf, maxp, intr_complete, dev, period); + devdbg(dev, + "status ep%din, %d bytes period %d", + usb_pipeendpoint(pipe), maxp, period); + } + } + return 0; +} + +/* Passes this packet up the stack, updating its accounting. + * Some link protocols batch packets, so their rx_fixup paths + * can return clones as well as just modify the original skb. + */ +static +void axusbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) +{ + int status; + + skb->dev = dev->net; + skb->protocol = eth_type_trans (skb, dev->net); + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + if (netif_msg_rx_status (dev)) + devdbg (dev, "< rx, len %zu, type 0x%x", + skb->len + sizeof (struct ethhdr), skb->protocol); + memset (skb->cb, 0, sizeof (struct skb_data)); + status = netif_rx (skb); + if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev)) + devdbg (dev, "netif_rx status %d", status); +} + +/*------------------------------------------------------------------------- + * + * Network Device Driver (peer link to "Host Device", from USB host) + * + *-------------------------------------------------------------------------*/ + +static +int axusbnet_change_mtu (struct net_device *net, int new_mtu) +{ + struct usbnet *dev = netdev_priv(net); + int ll_mtu = new_mtu + net->hard_header_len; + int old_hard_mtu = dev->hard_mtu; + int old_rx_urb_size = dev->rx_urb_size; + + if (new_mtu <= 0) + return -EINVAL; + // no second zero-length packet read wanted after mtu-sized packets + if ((ll_mtu % dev->maxpacket) == 0) + return -EDOM; + net->mtu = new_mtu; + + dev->hard_mtu = net->mtu + net->hard_header_len; + if (dev->rx_urb_size == old_hard_mtu) { + dev->rx_urb_size = dev->hard_mtu; + if (dev->rx_urb_size > old_rx_urb_size) + axusbnet_unlink_rx_urbs(dev); + } + + return 0; +} + +static struct net_device_stats *axusbnet_get_stats (struct net_device *net) +{ + struct usbnet *dev = netdev_priv (net); + return &dev->stats; +} + +/*-------------------------------------------------------------------------*/ + +/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from + * completion callbacks. 2.5 should have fixed those bugs... + */ + +static void +defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list) +{ + unsigned long flags; + + spin_lock_irqsave(&list->lock, flags); + __skb_unlink(skb, list); + spin_unlock(&list->lock); + spin_lock(&dev->done.lock); + __skb_queue_tail(&dev->done, skb); + if (dev->done.qlen == 1) + tasklet_schedule(&dev->bh); + spin_unlock_irqrestore(&dev->done.lock, flags); +} + +/* some work can't be done in tasklets, so we use keventd + * + * NOTE: annoying asymmetry: if it's active, schedule_work() fails, + * but tasklet_schedule() doesn't. hope the failure is rare. + */ +static +void axusbnet_defer_kevent (struct usbnet *dev, int work) +{ + set_bit (work, &dev->flags); + if (!schedule_work (&dev->kevent)) + deverr (dev, "kevent %d may have been dropped", work); + else + devdbg (dev, "kevent %d scheduled", work); +} + +/*-------------------------------------------------------------------------*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +static void rx_complete (struct urb *urb, struct pt_regs *regs); +#else +static void rx_complete (struct urb *urb); +#endif + +static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) +{ + struct sk_buff *skb; + struct skb_data *entry; + int retval = 0; + unsigned long lockflags; + size_t size = dev->rx_urb_size; + struct driver_info *info = dev->driver_info; + u8 align; + +#if (AX_FORCE_BUFF_ALIGN) + align = 0; +#else + if (!(info->flags & FLAG_HW_IP_ALIGNMENT)) + align = NET_IP_ALIGN; + else + align = 0; +#endif + + if ((skb = alloc_skb (size + align, flags)) == NULL) { + + if (netif_msg_rx_err (dev)) + devdbg (dev, "no rx skb"); + + if((dev->rx_urb_size > 2048) && dev->rx_size) { + dev->rx_size--; + dev->rx_urb_size = AX88772B_BULKIN_SIZE[dev->rx_size].size; + + ax8817x_write_cmd_async (dev, 0x2A, + AX88772B_BULKIN_SIZE[dev->rx_size].byte_cnt, + AX88772B_BULKIN_SIZE[dev->rx_size].threshold, + 0, NULL); + } + + if (!(dev->flags & EVENT_RX_MEMORY)) + axusbnet_defer_kevent (dev, EVENT_RX_MEMORY); + usb_free_urb (urb); + return; + } + + if (align) + skb_reserve (skb, NET_IP_ALIGN); + + entry = (struct skb_data *) skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->state = rx_start; + entry->length = 0; + + usb_fill_bulk_urb (urb, dev->udev, dev->in, + skb->data, size, rx_complete, skb); + + spin_lock_irqsave (&dev->rxq.lock, lockflags); + + if (netif_running (dev->net) + && netif_device_present (dev->net) + && !test_bit (EVENT_RX_HALT, &dev->flags)) { + switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { + case -EPIPE: + axusbnet_defer_kevent (dev, EVENT_RX_HALT); + break; + case -ENOMEM: + axusbnet_defer_kevent (dev, EVENT_RX_MEMORY); + break; + case -ENODEV: + if (netif_msg_ifdown (dev)) + devdbg (dev, "device gone"); + netif_device_detach (dev->net); + break; + default: + if (netif_msg_rx_err (dev)) + devdbg (dev, "rx submit, %d", retval); + tasklet_schedule (&dev->bh); + break; + case 0: + __skb_queue_tail (&dev->rxq, skb); + } + } else { + if (netif_msg_ifdown (dev)) + devdbg (dev, "rx: stopped"); + retval = -ENOLINK; + } + spin_unlock_irqrestore (&dev->rxq.lock, lockflags); + if (retval) { + dev_kfree_skb_any (skb); + usb_free_urb (urb); + } +} + + +/*-------------------------------------------------------------------------*/ + +static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) +{ + if (dev->driver_info->rx_fixup + && !dev->driver_info->rx_fixup (dev, skb)) + goto error; + // else network stack removes extra byte if we forced a short packet + + if (skb->len) + axusbnet_skb_return (dev, skb); + else { + if (netif_msg_rx_err (dev)) + devdbg (dev, "drop"); +error: + dev->stats.rx_errors++; + skb_queue_tail (&dev->done, skb); + } +} + +/*-------------------------------------------------------------------------*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +static void rx_complete (struct urb *urb, struct pt_regs *regs) +#else +static void rx_complete (struct urb *urb) +#endif +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct skb_data *entry = (struct skb_data *) skb->cb; + struct usbnet *dev = entry->dev; + int urb_status = urb->status; + + skb_put (skb, urb->actual_length); + entry->state = rx_done; + entry->urb = NULL; + + switch (urb_status) { + /* success */ + case 0: + if (skb->len < dev->net->hard_header_len) { + entry->state = rx_cleanup; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + if (netif_msg_rx_err (dev)) + devdbg (dev, "rx length %d", skb->len); + } + break; + + /* stalls need manual reset. this is rare ... except that + * when going through USB 2.0 TTs, unplug appears this way. + * we avoid the highspeed version of the ETIMEDOUT/EILSEQ + * storm, recovering as needed. + */ + case -EPIPE: + dev->stats.rx_errors++; + axusbnet_defer_kevent (dev, EVENT_RX_HALT); + // FALLTHROUGH + + /* software-driven interface shutdown */ + case -ECONNRESET: /* async unlink */ + case -ESHUTDOWN: /* hardware gone */ + if (netif_msg_ifdown (dev)) + devdbg (dev, "rx shutdown, code %d", urb_status); + goto block; + + /* we get controller i/o faults during khubd disconnect() delays. + * throttle down resubmits, to avoid log floods; just temporarily, + * so we still recover when the fault isn't a khubd delay. + */ + case -EPROTO: + case -ETIME: + case -EILSEQ: + dev->stats.rx_errors++; + if (!timer_pending (&dev->delay)) { + mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); + if (netif_msg_link (dev)) + devdbg (dev, "rx throttle %d", urb_status); + } +block: + entry->state = rx_cleanup; + entry->urb = urb; + urb = NULL; + break; + + /* data overrun ... flush fifo? */ + case -EOVERFLOW: + dev->stats.rx_over_errors++; + // FALLTHROUGH + + default: + entry->state = rx_cleanup; + dev->stats.rx_errors++; + if (netif_msg_rx_err (dev)) + devdbg (dev, "rx status %d", urb_status); + break; + } + + defer_bh(dev, skb, &dev->rxq); + + if (urb) { + if (netif_running (dev->net) + && !test_bit (EVENT_RX_HALT, &dev->flags)) { + rx_submit (dev, urb, GFP_ATOMIC); + return; + } + usb_free_urb (urb); + } + if (netif_msg_rx_err (dev)) + devdbg (dev, "no read resubmitted"); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +static void intr_complete (struct urb *urb, struct pt_regs *regs) +#else +static void intr_complete (struct urb *urb) +#endif +{ + struct usbnet *dev = urb->context; + int status = urb->status; + + switch (status) { + /* success */ + case 0: + dev->driver_info->status(dev, urb); + break; + + /* software-driven interface shutdown */ + case -ENOENT: /* urb killed */ + case -ESHUTDOWN: /* hardware gone */ + if (netif_msg_ifdown (dev)) + devdbg (dev, "intr shutdown, code %d", status); + return; + + /* NOTE: not throttling like RX/TX, since this endpoint + * already polls infrequently + */ + default: + devdbg (dev, "intr status %d", status); + break; + } + + if (!netif_running (dev->net)) + return; + + memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); + status = usb_submit_urb (urb, GFP_ATOMIC); + if (status != 0 && netif_msg_timer (dev)) + deverr(dev, "intr resubmit --> %d", status); +} + +/*-------------------------------------------------------------------------*/ + +// unlink pending rx/tx; completion handlers do all other cleanup + +static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) +{ + unsigned long flags; + struct sk_buff *skb, *skbnext; + int count = 0; + + spin_lock_irqsave (&q->lock, flags); + skb_queue_walk_safe(q, skb, skbnext) { + struct skb_data *entry; + struct urb *urb; + int retval; + + entry = (struct skb_data *) skb->cb; + urb = entry->urb; + + // during some PM-driven resume scenarios, + // these (async) unlinks complete immediately + retval = usb_unlink_urb (urb); + if (retval != -EINPROGRESS && retval != 0) + devdbg (dev, "unlink urb err, %d", retval); + else + count++; + } + spin_unlock_irqrestore (&q->lock, flags); + return count; +} + +// Flush all pending rx urbs +// minidrivers may need to do this when the MTU changes + +static +void axusbnet_unlink_rx_urbs(struct usbnet *dev) +{ + if (netif_running(dev->net)) { + (void) unlink_urbs (dev, &dev->rxq); + tasklet_schedule(&dev->bh); + } +} + +/*-------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static +int axusbnet_stop (struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct driver_info *info = dev->driver_info; + int temp; + int retval; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) + DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); +#else + DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); +#endif + DECLARE_WAITQUEUE (wait, current); + + netif_stop_queue (net); + + if (netif_msg_ifdown (dev)) + devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", + dev->stats.rx_packets, dev->stats.tx_packets, + dev->stats.rx_errors, dev->stats.tx_errors + ); + + /* allow minidriver to stop correctly (wireless devices to turn off + * radio etc) */ + if (info->stop) { + retval = info->stop(dev); + if (retval < 0 && netif_msg_ifdown(dev)) + devinfo(dev, + "stop fail (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + } + + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { + /* ensure there are no more active urbs */ + add_wait_queue(&unlink_wakeup, &wait); + dev->wait = &unlink_wakeup; + temp = unlink_urbs(dev, &dev->txq) + + unlink_urbs(dev, &dev->rxq); + + /* maybe wait for deletions to finish. */ + while (!skb_queue_empty(&dev->rxq) + && !skb_queue_empty(&dev->txq) + && !skb_queue_empty(&dev->done)) { + msleep(UNLINK_TIMEOUT_MS); + if (netif_msg_ifdown(dev)) + devdbg(dev, "waited for %d urb completions", + temp); + } + dev->wait = NULL; + remove_wait_queue(&unlink_wakeup, &wait); + } + + usb_kill_urb(dev->interrupt); + + /* deferred work (task, timer, softirq) must also stop. + * can't flush_scheduled_work() until we drop rtnl (later), + * else workers could deadlock; so make workers a NOP. + */ + dev->flags = 0; + del_timer_sync (&dev->delay); + tasklet_kill (&dev->bh); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +// posts reads, and enables write queuing + +// precondition: never called in_interrupt + +static +int axusbnet_open (struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + int retval = 0; + struct driver_info *info = dev->driver_info; + + // put into "known safe" state + if (info->reset && (retval = info->reset (dev)) < 0) { + if (netif_msg_ifup (dev)) + devinfo (dev, + "open reset fail (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + goto done; + } + + // insist peer be connected + if (info->check_connect && (retval = info->check_connect (dev)) < 0) { + if (netif_msg_ifup (dev)) + devdbg (dev, "can't open; %d", retval); + goto done; + } + + /* start any status interrupt transfer */ + if (dev->interrupt) { + retval = usb_submit_urb (dev->interrupt, GFP_KERNEL); + if (retval < 0) { + if (netif_msg_ifup (dev)) + deverr (dev, "intr submit %d", retval); + goto done; + } + } + + netif_start_queue (net); + if (netif_msg_ifup (dev)) { + char *framing; + + if (dev->driver_info->flags & FLAG_FRAMING_NC) + framing = "NetChip"; + else if (dev->driver_info->flags & FLAG_FRAMING_GL) + framing = "GeneSys"; + else if (dev->driver_info->flags & FLAG_FRAMING_Z) + framing = "Zaurus"; + else if (dev->driver_info->flags & FLAG_FRAMING_RN) + framing = "RNDIS"; + else if (dev->driver_info->flags & FLAG_FRAMING_AX) + framing = "ASIX"; + else + framing = "simple"; + + devinfo (dev, "open: enable queueing " + "(rx %d, tx %d) mtu %d %s framing", + (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu, + framing); + } + + // delay posting reads until we're fully open + tasklet_schedule (&dev->bh); + return retval; +done: + return retval; +} + +/*-------------------------------------------------------------------------*/ + +/* ethtool methods; minidrivers may need to add some more, but + * they'll probably want to use this base set. + */ + +static +int axusbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + + if (!dev->mii.mdio_read) + return -EOPNOTSUPP; + + return mii_ethtool_gset(&dev->mii, cmd); +} + +static +int axusbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + int retval; + + if (!dev->mii.mdio_write) + return -EOPNOTSUPP; + + retval = mii_ethtool_sset(&dev->mii, cmd); + + /* link speed/duplex might have changed */ + if (dev->driver_info->link_reset) + dev->driver_info->link_reset(dev); + + return retval; + +} + +static +u32 axusbnet_get_link (struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + /* If a check_connect is defined, return its result */ + if (dev->driver_info->check_connect) + return dev->driver_info->check_connect (dev) == 0; + + /* if the device has mii operations, use those */ + if (dev->mii.mdio_read) + return mii_link_ok(&dev->mii); + + /* Otherwise, dtrt for drivers calling netif_carrier_{on,off} */ + return ethtool_op_get_link(net); +} + +static +int axusbnet_nway_reset(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + if (!dev->mii.mdio_write) + return -EOPNOTSUPP; + + return mii_nway_restart(&dev->mii); +} + +static +void axusbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) +{ + struct usbnet *dev = netdev_priv(net); + + strncpy (info->driver, dev->driver_name, sizeof info->driver); + strncpy (info->version, DRIVER_VERSION, sizeof info->version); + strncpy (info->fw_version, dev->driver_info->description, + sizeof info->fw_version); + usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); +} + +static +u32 axusbnet_get_msglevel (struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + return dev->msg_enable; +} + +static +void axusbnet_set_msglevel (struct net_device *net, u32 level) +{ + struct usbnet *dev = netdev_priv(net); + + dev->msg_enable = level; +} + +/* drivers may override default ethtool_ops in their bind() routine */ +static struct ethtool_ops axusbnet_ethtool_ops = { + .get_settings = axusbnet_get_settings, + .set_settings = axusbnet_set_settings, + .get_link = axusbnet_get_link, + .nway_reset = axusbnet_nway_reset, + .get_drvinfo = axusbnet_get_drvinfo, + .get_msglevel = axusbnet_get_msglevel, + .set_msglevel = axusbnet_set_msglevel, +}; + +/*-------------------------------------------------------------------------*/ + +/* work that cannot be done in interrupt context uses keventd. + * + * NOTE: with 2.5 we could do more of this using completion callbacks, + * especially now that control transfers can be queued. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void kevent (void *data) +{ + struct usbnet *dev = (struct usbnet *)data; +#else +static void kevent (struct work_struct *work) +{ + struct usbnet *dev = + container_of(work, struct usbnet, kevent); +#endif + int status; + + /* usb_clear_halt() needs a thread context */ + if (test_bit (EVENT_TX_HALT, &dev->flags)) { + + unlink_urbs (dev, &dev->txq); + status = usb_clear_halt (dev->udev, dev->out); + if (status < 0 + && status != -EPIPE + && status != -ESHUTDOWN) { + if (netif_msg_tx_err (dev)) + deverr (dev, "can't clear tx halt, status %d", + status); + } else { + clear_bit (EVENT_TX_HALT, &dev->flags); + if (status != -ESHUTDOWN) + netif_wake_queue (dev->net); + } + } + if (test_bit (EVENT_RX_HALT, &dev->flags)) { + + unlink_urbs (dev, &dev->rxq); + status = usb_clear_halt (dev->udev, dev->in); + if (status < 0 + && status != -EPIPE + && status != -ESHUTDOWN) { + if (netif_msg_rx_err (dev)) + deverr (dev, "can't clear rx halt, status %d", + status); + } else { + clear_bit (EVENT_RX_HALT, &dev->flags); + tasklet_schedule (&dev->bh); + } + } + + /* tasklet could resubmit itself forever if memory is tight */ + if (test_bit (EVENT_RX_MEMORY, &dev->flags)) { + struct urb *urb = NULL; + + if (netif_running (dev->net)) + urb = usb_alloc_urb (0, GFP_KERNEL); + else + clear_bit (EVENT_RX_MEMORY, &dev->flags); + if (urb != NULL) { + clear_bit (EVENT_RX_MEMORY, &dev->flags); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) + urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + rx_submit (dev, urb, GFP_KERNEL); + tasklet_schedule (&dev->bh); + } + } + + if (test_bit (EVENT_LINK_RESET, &dev->flags)) { + struct driver_info *info = dev->driver_info; + int retval = 0; + + clear_bit (EVENT_LINK_RESET, &dev->flags); + if(info->link_reset && (retval = info->link_reset(dev)) < 0) { + devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + } + } + + if (dev->flags) + devdbg (dev, "kevent done, flags = 0x%lx", + dev->flags); +} + +/*-------------------------------------------------------------------------*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +static void tx_complete (struct urb *urb, struct pt_regs *regs) +#else +static void tx_complete (struct urb *urb) +#endif +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct skb_data *entry = (struct skb_data *) skb->cb; + struct usbnet *dev = entry->dev; + + if (urb->status == 0) { + dev->stats.tx_packets++; + dev->stats.tx_bytes += entry->length; + } else { + dev->stats.tx_errors++; + + switch (urb->status) { + case -EPIPE: + axusbnet_defer_kevent (dev, EVENT_TX_HALT); + break; + + /* software-driven interface shutdown */ + case -ECONNRESET: // async unlink + case -ESHUTDOWN: // hardware gone + break; + + // like rx, tx gets controller i/o faults during khubd delays + // and so it uses the same throttling mechanism. + case -EPROTO: + case -ETIME: + case -EILSEQ: + if (!timer_pending (&dev->delay)) { + mod_timer (&dev->delay, + jiffies + THROTTLE_JIFFIES); + if (netif_msg_link (dev)) + devdbg (dev, "tx throttle %d", + urb->status); + } + netif_stop_queue (dev->net); + break; + default: + if (netif_msg_tx_err (dev)) + devdbg (dev, "tx err %d", entry->urb->status); + break; + } + } + + urb->dev = NULL; + entry->state = tx_done; + defer_bh(dev, skb, &dev->txq); +} + +/*-------------------------------------------------------------------------*/ + +static +void axusbnet_tx_timeout (struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + unlink_urbs (dev, &dev->txq); + tasklet_schedule (&dev->bh); + + // FIXME: device recovery -- reset? +} + +/*-------------------------------------------------------------------------*/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +static int +#else +static netdev_tx_t +#endif +axusbnet_start_xmit (struct sk_buff *skb, + struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + int length; + struct urb *urb = NULL; + struct skb_data *entry; + struct driver_info *info = dev->driver_info; + unsigned long flags; + int retval; + + // some devices want funky USB-level framing, for + // win32 driver (usually) and/or hardware quirks + if (info->tx_fixup) { + skb = info->tx_fixup (dev, skb, GFP_ATOMIC); + if (!skb) { + if (netif_msg_tx_err (dev)) + devdbg (dev, "can't tx_fixup skb"); + goto drop; + } + } + length = skb->len; + + if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { + if (netif_msg_tx_err (dev)) + devdbg (dev, "no urb"); + goto drop; + } + + entry = (struct skb_data *) skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->state = tx_start; + entry->length = length; + + usb_fill_bulk_urb (urb, dev->udev, dev->out, + skb->data, skb->len, tx_complete, skb); + + /* don't assume the hardware handles USB_ZERO_PACKET + * NOTE: strictly conforming cdc-ether devices should expect + * the ZLP here, but ignore the one-byte packet. + */ + if (!(info->flags & FLAG_SEND_ZLP) && (length % dev->maxpacket) == 0) { + urb->transfer_buffer_length++; + if (skb_tailroom(skb)) { + skb->data[skb->len] = 0; + __skb_put(skb, 1); + } + } + + spin_lock_irqsave (&dev->txq.lock, flags); + + switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { + case -EPIPE: + netif_stop_queue (net); + axusbnet_defer_kevent (dev, EVENT_TX_HALT); + break; + default: + if (netif_msg_tx_err (dev)) + devdbg (dev, "tx: submit urb err %d", retval); + break; + case 0: + net->trans_start = jiffies; + __skb_queue_tail (&dev->txq, skb); + if (dev->txq.qlen >= TX_QLEN (dev)) + netif_stop_queue (net); + } + spin_unlock_irqrestore (&dev->txq.lock, flags); + + if (retval) { + if (netif_msg_tx_err (dev)) + devdbg (dev, "drop, code %d", retval); +drop: + dev->stats.tx_dropped++; + if (skb) + dev_kfree_skb_any (skb); + usb_free_urb (urb); + } else if (netif_msg_tx_queued (dev)) { + devdbg (dev, "> tx, len %d, type 0x%x", + length, skb->protocol); + } + return NETDEV_TX_OK; +} + +/*-------------------------------------------------------------------------*/ + +// tasklet (work deferred from completions, in_irq) or timer + +static void axusbnet_bh (unsigned long param) +{ + struct usbnet *dev = (struct usbnet *) param; + struct sk_buff *skb; + struct skb_data *entry; + + while ((skb = skb_dequeue (&dev->done))) { + entry = (struct skb_data *) skb->cb; + switch (entry->state) { + case rx_done: + entry->state = rx_cleanup; + rx_process (dev, skb); + continue; + case tx_done: + case rx_cleanup: + usb_free_urb (entry->urb); + dev_kfree_skb (skb); + continue; + default: + devdbg (dev, "bogus skb state %d", entry->state); + } + } + + // waiting for all pending urbs to complete? + if (dev->wait) { + if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { + wake_up (dev->wait); + } + + // or are we maybe short a few urbs? + } else if (netif_running (dev->net) + && netif_device_present (dev->net) + && !timer_pending (&dev->delay) + && !test_bit (EVENT_RX_HALT, &dev->flags)) { + int temp = dev->rxq.qlen; + int qlen = RX_QLEN (dev); + + if (temp < qlen) { + struct urb *urb; + int i; + + // don't refill the queue all at once + for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { + urb = usb_alloc_urb (0, GFP_ATOMIC); + if (urb != NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) + urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + rx_submit (dev, urb, GFP_ATOMIC); + } + } + if (temp != dev->rxq.qlen && netif_msg_link (dev)) + devdbg (dev, "rxqlen %d --> %d", + temp, dev->rxq.qlen); + if (dev->rxq.qlen < qlen) + tasklet_schedule (&dev->bh); + } + if (dev->txq.qlen < TX_QLEN (dev)) + netif_wake_queue (dev->net); + } +} + + +/*------------------------------------------------------------------------- + * + * USB Device Driver support + * + *-------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static +void axusbnet_disconnect (struct usb_interface *intf) +{ + struct usbnet *dev; + struct usb_device *xdev; + struct net_device *net; + + dev = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + if (!dev) + return; + + xdev = interface_to_usbdev (intf); + + if (netif_msg_probe (dev)) + devinfo (dev, "unregister '%s' usb-%s-%s, %s", + intf->dev.driver->name, + xdev->bus->bus_name, xdev->devpath, + dev->driver_info->description); + + net = dev->net; + unregister_netdev (net); + + /* we don't hold rtnl here ... */ + flush_scheduled_work (); + + if (dev->driver_info->unbind) + dev->driver_info->unbind (dev, intf); + + free_netdev(net); + usb_put_dev (xdev); +} + +/*-------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static int +axusbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) +{ + struct usbnet *dev; + struct net_device *net; + struct usb_host_interface *interface; + struct driver_info *info; + struct usb_device *xdev; + int status; + const char *name; + + name = udev->dev.driver->name; + info = (struct driver_info *) prod->driver_info; + if (!info) { + printk (KERN_ERR "blacklisted by %s\n", name); + return -ENODEV; + } + xdev = interface_to_usbdev (udev); + interface = udev->cur_altsetting; + + usb_get_dev (xdev); + + status = -ENOMEM; + + // set up our own records + net = alloc_etherdev(sizeof(*dev)); + if (!net) { + dbg ("can't kmalloc dev"); + goto out; + } + + dev = netdev_priv(net); + dev->udev = xdev; + dev->intf = udev; + dev->driver_info = info; + dev->driver_name = name; + dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV + | NETIF_MSG_PROBE | NETIF_MSG_LINK); + skb_queue_head_init (&dev->rxq); + skb_queue_head_init (&dev->txq); + skb_queue_head_init (&dev->done); + dev->bh.func = axusbnet_bh; + dev->bh.data = (unsigned long) dev; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK (&dev->kevent, kevent, dev); +#else + INIT_WORK (&dev->kevent, kevent); +#endif + + dev->delay.function = axusbnet_bh; + dev->delay.data = (unsigned long) dev; + init_timer (&dev->delay); +// mutex_init (&dev->phy_mutex); + + dev->net = net; + + /* rx and tx sides can use different message sizes; + * bind() should set rx_urb_size in that case. + */ + dev->hard_mtu = net->mtu + net->hard_header_len; + +#if 0 +// dma_supported() is deeply broken on almost all architectures + // possible with some EHCI controllers + if (dma_supported (&udev->dev, DMA_BIT_MASK(64))) + net->features |= NETIF_F_HIGHDMA; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) + net->open = axusbnet_open, + net->stop = axusbnet_stop, + net->hard_start_xmit = axusbnet_start_xmit, + net->tx_timeout = axusbnet_tx_timeout, + net->get_stats = axusbnet_get_stats; +#endif + + net->watchdog_timeo = TX_TIMEOUT_JIFFIES; + net->ethtool_ops = &axusbnet_ethtool_ops; + + // allow device-specific bind/init procedures + // NOTE net->name still not usable ... + status = info->bind (dev, udev); + if (status < 0) { + deverr(dev, "Binding device failed: %d", status); + goto out1; + } + + /* maybe the remote can't receive an Ethernet MTU */ + if (net->mtu > (dev->hard_mtu - net->hard_header_len)) + net->mtu = dev->hard_mtu - net->hard_header_len; + + status = init_status (dev, udev); + if (status < 0) + goto out3; + + if (!dev->rx_urb_size) + dev->rx_urb_size = dev->hard_mtu; + dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); + + SET_NETDEV_DEV(net, &udev->dev); + status = register_netdev (net); + if (status) { + deverr(dev, "net device registration failed: %d", status); + goto out3; + } + + if (netif_msg_probe (dev)) + devinfo (dev, "register '%s' at usb-%s-%s, %s, %pM", + udev->dev.driver->name, + xdev->bus->bus_name, xdev->devpath, + dev->driver_info->description, + net->dev_addr); + + // ok, it's ready to go. + usb_set_intfdata (udev, dev); + + // start as if the link is up + netif_device_attach (net); + + return 0; + +out3: + if (info->unbind) + info->unbind (dev, udev); +out1: + free_netdev(net); +out: + usb_put_dev(xdev); + return status; +} + +/*-------------------------------------------------------------------------*/ + +/* + * suspend the whole driver as soon as the first interface is suspended + * resume only when the last interface is resumed + */ + +static int axusbnet_suspend (struct usb_interface *intf, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) +pm_message_t message) +#else +u32 message) +#endif +{ + struct usbnet *dev = usb_get_intfdata(intf); + + if (!dev->suspend_count++) { + /* + * accelerate emptying of the rx and queues, to avoid + * having everything error out. + */ + netif_device_detach (dev->net); + (void) unlink_urbs (dev, &dev->rxq); + (void) unlink_urbs (dev, &dev->txq); + /* + * reattach so runtime management can use and + * wake the device + */ + netif_device_attach (dev->net); + } + return 0; +} + +static int +axusbnet_resume (struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + + if (!--dev->suspend_count) + tasklet_schedule (&dev->bh); + + return 0; +} + diff --git a/drivers/net/usb/axusbnet.h b/drivers/net/usb/axusbnet.h new file mode 100644 index 000000000000..d492de3b80e1 --- /dev/null +++ b/drivers/net/usb/axusbnet.h @@ -0,0 +1,208 @@ +/* + * USB Networking Link Interface + * + * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net> + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_USB_USBNET_H +#define __LINUX_USB_USBNET_H + +#ifndef gfp_t +#define gfp_t int +#endif + +/* interface from usbnet core to each USB networking link we handle */ +struct usbnet { + /* housekeeping */ + struct usb_device *udev; + struct usb_interface *intf; + struct driver_info *driver_info; + const char *driver_name; + void *driver_priv; + wait_queue_head_t *wait; +// struct mutex phy_mutex; + unsigned char suspend_count; + + /* i/o info: pipes etc */ + unsigned in, out; + struct usb_host_endpoint *status; + unsigned maxpacket; + struct timer_list delay; + + /* protocol/interface state */ + struct net_device *net; + struct net_device_stats stats; + int msg_enable; + unsigned long data [5]; + u32 xid; + u32 hard_mtu; /* count any extra framing */ + size_t rx_urb_size; /* size for rx urbs */ + struct mii_if_info mii; + + /* various kinds of pending driver work */ + struct sk_buff_head rxq; + struct sk_buff_head txq; + struct sk_buff_head done; + struct sk_buff_head rxq_pause; + struct urb *interrupt; + struct tasklet_struct bh; + + struct work_struct kevent; + unsigned long flags; +# define EVENT_TX_HALT 0 +# define EVENT_RX_HALT 1 +# define EVENT_RX_MEMORY 2 +# define EVENT_STS_SPLIT 3 +# define EVENT_LINK_RESET 4 +# define EVENT_RX_PAUSED 5 + + void *priv; /* point to minidriver private data */ + unsigned char rx_size; +}; + +static inline struct usb_driver *driver_of(struct usb_interface *intf) +{ + return to_usb_driver(intf->dev.driver); +} + +/* interface from the device/framing level "minidriver" to core */ +struct driver_info { + char *description; + + int flags; +/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ +#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ +#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ +#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ +#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */ + +#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ +#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ + +#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ +#define FLAG_WLAN 0x0080 /* use "wlan%d" names */ +#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */ +#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */ +#define FLAG_HW_IP_ALIGNMENT 0x0400 /* AX88772B support hardware IP alignment */ + + + /* init device ... can sleep, or cause probe() failure */ + int (*bind)(struct usbnet *, struct usb_interface *); + + /* cleanup device ... can sleep, but can't fail */ + void (*unbind)(struct usbnet *, struct usb_interface *); + + /* reset device ... can sleep */ + int (*reset)(struct usbnet *); + + /* stop device ... can sleep */ + int (*stop)(struct usbnet *); + + /* see if peer is connected ... can sleep */ + int (*check_connect)(struct usbnet *); + + /* for status polling */ + void (*status)(struct usbnet *, struct urb *); + + /* link reset handling, called from defer_kevent */ + int (*link_reset)(struct usbnet *); + + /* fixup rx packet (strip framing) */ + int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); + + /* fixup tx packet (add framing) */ + struct sk_buff *(*tx_fixup)(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags); + + /* early initialization code, can sleep. This is for minidrivers + * having 'subminidrivers' that need to do extra initialization + * right after minidriver have initialized hardware. */ + int (*early_init)(struct usbnet *dev); + + /* called by minidriver when receiving indication */ + void (*indication)(struct usbnet *dev, void *ind, int indlen); + + /* for new devices, use the descriptor-reading code instead */ + int in; /* rx endpoint */ + int out; /* tx endpoint */ + + unsigned long data; /* Misc driver specific data */ +}; + +/* Drivers that reuse some of the standard USB CDC infrastructure + * (notably, using multiple interfaces according to the CDC + * union descriptor) get some helper code. + */ +struct cdc_state { + struct usb_cdc_header_desc *header; + struct usb_cdc_union_desc *u; + struct usb_cdc_ether_desc *ether; + struct usb_interface *control; + struct usb_interface *data; +}; + +/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ +#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ + |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ + |USB_CDC_PACKET_TYPE_PROMISCUOUS \ + |USB_CDC_PACKET_TYPE_DIRECTED) + + +/* we record the state for each of our queued skbs */ +enum skb_state { + illegal = 0, + tx_start, tx_done, + rx_start, rx_done, rx_cleanup +}; + +struct skb_data { /* skb->cb is one of these */ + struct urb *urb; + struct usbnet *dev; + enum skb_state state; + size_t length; +}; + +#ifndef skb_queue_walk_safe +#define skb_queue_walk_safe(queue, skb, tmp) \ + for (skb = (queue)->next, tmp = skb->next; \ + skb != (struct sk_buff *)(queue); \ + skb = tmp, tmp = skb->next) +#endif + +/* messaging support includes the interface name, so it must not be + * used before it has one ... notably, in minidriver bind() calls. + */ +#ifdef DEBUG +#define devdbg(usbnet, fmt, arg...) \ + printk("%s: " fmt "\n" , (usbnet)->net->name , ## arg) +#else +#define devdbg(usbnet, fmt, arg...) \ + ({ if (0) printk("%s: " fmt "\n" , (usbnet)->net->name , \ + ## arg); 0; }) +#endif + +#define deverr(usbnet, fmt, arg...) \ + printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg) +#define devwarn(usbnet, fmt, arg...) \ + printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg) + +#define devinfo(usbnet, fmt, arg...) \ + printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \ + + +#endif /* __LINUX_USB_USBNET_H */ diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 9ab8f3fb68ef..c9cac10c6a3e 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -64,6 +64,7 @@ struct tps6586x_regulator { int enable_reg[2]; int *voltages; int delay; /* delay in us for regulator to stabilize */ + enum tps6586x_type type; /* for DVM regulators */ int go_reg; @@ -236,6 +237,13 @@ static int tps6586x_sm2_voltages[] = { 4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550, }; +static int tps6586x_sm2fortythree_voltages[] = { + 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, + 1225, 1250, 1275, 1300, 1325, 1350, 1375, 1400, + 1425, 1450, 1475, 1500, 1525, 1550, 1575, 1600, + 1625, 1650, 1675, 1700, 1725, 1750, 1775, 1800, +}; + static int tps6586x_dvm_voltages[] = { 725, 750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000, 1025, 1050, 1075, 1100, @@ -243,7 +251,7 @@ static int tps6586x_dvm_voltages[] = { 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, }; -#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \ +#define TPS6586X_REGULATOR(_id, _type, vdata, _ops, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, en_time) \ .desc = { \ .name = "REG-" #_id, \ @@ -261,43 +269,62 @@ static int tps6586x_dvm_voltages[] = { .enable_reg[1] = TPS6586X_SUPPLY##ereg1, \ .enable_bit[1] = (ebit1), \ .voltages = tps6586x_##vdata##_voltages, \ - .delay = en_time, + .delay = en_time, \ + .type = (_type), #define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ .go_reg = TPS6586X_##goreg, \ .go_bit = (gobit), -#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \ +#define TPS6586X_LDO(_id, type, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, en_time) \ { \ - TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1, en_time) \ + TPS6586X_REGULATOR(_id, type, vdata, ldo_ops, vreg, shift, \ + nbits, ereg0, ebit0, ereg1, ebit1, en_time) \ } -#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \ +#define TPS6586X_DVM(_id, type, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, goreg, gobit, en_time) \ { \ - TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1, en_time) \ + TPS6586X_REGULATOR(_id, type, vdata, dvm_ops, vreg, shift, \ + nbits, ereg0, ebit0, ereg1, ebit1, en_time) \ TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ } +/* Note: type ANY means universal, search order matters, place ANY last */ static struct tps6586x_regulator tps6586x_regulator[] = { - TPS6586X_LDO(LDO_0, ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0, 4000), - TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1, 4000), - TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2, 3000), - TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6, 3000), - TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4, 15000), - TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5, 15000), - TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6, 15000), - TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7, 3000), - TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7, 0), - TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7, 0), - - TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6, 3000), - TPS6586X_DVM(SM_0, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2, 4000), - TPS6586X_DVM(SM_1, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0, 4000), - TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6, 15000), + TPS6586X_LDO(LDO_0, TPS6586X_ANY, ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0, + 4000), + TPS6586X_LDO(LDO_1, TPS6586X_ANY, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1, + 4000), + TPS6586X_DVM(LDO_2, TPS6586X_ANY, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, + VCC2, 6, 3000), + TPS6586X_LDO(LDO_3, TPS6586X_ANY, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2, + 3000), + TPS6586X_DVM(LDO_4, TPS6586X_ANY, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, + VCC1, 6, 15000), + TPS6586X_LDO(LDO_5, TPS6586X_ANY, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6, + 3000), + TPS6586X_LDO(LDO_6, TPS6586X_ANY, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4, + 15000), + TPS6586X_LDO(LDO_7, TPS6586X_ANY, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5, + 15000), + TPS6586X_LDO(LDO_8, TPS6586X_ANY, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6, + 15000), + TPS6586X_LDO(LDO_9, TPS6586X_ANY, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7, + 3000), + TPS6586X_LDO(LDO_RTC, TPS6586X_ANY, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7, + 0), + TPS6586X_DVM(SM_0, TPS6586X_ANY, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, + VCC1, 2, 4000), + TPS6586X_DVM(SM_1, TPS6586X_ANY, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, + VCC1, 0, 4000), + TPS6586X_DVM(SM_2, TPS658623, ldo4, SUPPLYV2, 0, 5, ENC, 3, END, 3, + VCC1, 6, 15000), + TPS6586X_DVM(SM_2, TPS658643, sm2fortythree, SUPPLYV2, 0, 5, ENC, 3, + END, 3, VCC1, 6, 15000), + TPS6586X_LDO(SM_2, TPS6586X_ANY, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7, + 0), }; /* @@ -399,14 +426,16 @@ static inline int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) return tps6586x_write(parent, reg, setting->slew_rate); } -static inline struct tps6586x_regulator *find_regulator_info(int id) +static inline struct tps6586x_regulator *find_regulator_info(int id, + enum tps6586x_type type) { struct tps6586x_regulator *ri; int i; for (i = 0; i < ARRAY_SIZE(tps6586x_regulator); i++) { ri = &tps6586x_regulator[i]; - if (ri->desc.id == id) + if ((ri->desc.id == id) && ((ri->type == type) || + (ri->type == TPS6586X_ANY))) return ri; } return NULL; @@ -421,7 +450,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing reulator %d\n", id); - ri = find_regulator_info(id); + ri = find_regulator_info(id, tps6586x_gettype(pdev->dev.parent)); if (ri == NULL) { dev_err(&pdev->dev, "invalid regulator ID specified\n"); return -EINVAL; diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index b39f2e1c1fe6..ce9761c79c51 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -205,3 +205,10 @@ config MAX1363_RING_BUFFER help Say yes here to include ring buffer support in the MAX1363 ADC driver. + +config STMPE_ADC + bool "ST Microelectronics STMPE ADC driver" + depends on MFD_STMPE + help + Say yes here to build support for ST Microelectronics STMPE + built in ADC block (stmpe811). diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index f02035139979..e54101c03121 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -40,3 +40,5 @@ obj-$(CONFIG_AD7816) += ad7816.o obj-$(CONFIG_ADT75) += adt75.o obj-$(CONFIG_ADT7310) += adt7310.o obj-$(CONFIG_ADT7410) += adt7410.o + +obj-$(CONFIG_STMPE_ADC) += stmpe-adc.o diff --git a/drivers/staging/iio/adc/stmpe-adc.c b/drivers/staging/iio/adc/stmpe-adc.c new file mode 100644 index 000000000000..3a9d6bee558d --- /dev/null +++ b/drivers/staging/iio/adc/stmpe-adc.c @@ -0,0 +1,334 @@ +/* + * stmpe.c - STMicroelectronics STMPE811 IIO ADC Driver + * + * 4 channel, 10/12-bit ADC + * + * Copyright (C) 2013 Toradex AG <stefan.agner@toradex.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/regulator/consumer.h> +#include <linux/of_platform.h> +#include <linux/err.h> + +#include <linux/mfd/stmpe.h> + +#include "../iio.h" +#include "adc.h" + +#define STMPE_REG_INT_STA 0x0B +#define STMPE_REG_ADC_INT_EN 0x0E +#define STMPE_REG_ADC_INT_STA 0x0F + +#define STMPE_REG_ADC_CTRL1 0x20 +#define STMPE_REG_ADC_CTRL2 0x21 +#define STMPE_REG_ADC_CAPT 0x22 +#define STMPE_REG_ADC_DATA_CH(channel) (0x30 + 2*channel) + +#define STMPE_ADC_CH(channel) ((1 << channel) & 0xff) + +#define STMPE_ADC_TIMEOUT (msecs_to_jiffies(1000)) + +struct stmpe_adc { + struct stmpe *stmpe; + struct clk *clk; + struct device *dev; + unsigned int irq; + + struct completion completion; + + u8 channel; + u32 value; + u8 sample_time; + u8 mod_12b; + u8 ref_sel; + u8 adc_freq; +}; + +static int stmpe_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct stmpe_adc *info = iio_priv(indio_dev); + unsigned long timeout; + + if (mask > 0) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + + info->channel = (u8)chan->scan_index; + stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN, + STMPE_ADC_CH(info->channel)); + + stmpe_reg_write(info->stmpe, STMPE_REG_ADC_CAPT, + STMPE_ADC_CH(info->channel)); + + timeout = wait_for_completion_interruptible_timeout + (&info->completion, STMPE_ADC_TIMEOUT); + + *val = info->value; + + mutex_unlock(&indio_dev->mlock); + + if (timeout == -ERESTARTSYS) + return -EINTR; + + if (timeout == 0) + return -ETIMEDOUT; + + return IIO_VAL_INT; +} + +static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) +{ + struct stmpe_adc *info = (struct stmpe_adc *)dev_id; + u8 data[2]; + int int_sta; + + int_sta = stmpe_reg_read(info->stmpe, STMPE_REG_ADC_INT_STA); + + /* Is the interrupt relevant */ + if (!(int_sta & STMPE_ADC_CH(info->channel))) + return IRQ_NONE; + + /* Read value */ + stmpe_block_read(info->stmpe, STMPE_REG_ADC_DATA_CH(info->channel), 2, + data); + info->value = ((u32)data[0] << 8) + data[1]; + + stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA, int_sta); + + complete(&info->completion); + + return IRQ_HANDLED; +} + +static const struct iio_info stmpe_adc_iio_info = { + .num_interrupt_lines = 1, + .read_raw = &stmpe_read_raw, + .driver_module = THIS_MODULE, +}; + +#define STMPE_EV_M \ + (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \ + | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) +#define STMPE_INFO_MASK (1 << IIO_CHAN_INFO_SCALE_SHARED) + +static const struct iio_chan_spec stmpe_adc_all_iio_channels[] = { + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, STMPE_INFO_MASK, + 0, 0, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 1, 0, STMPE_INFO_MASK, + 0, 1, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 2, 0, STMPE_INFO_MASK, + 0, 2, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 3, 0, STMPE_INFO_MASK, + 0, 3, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 4, 0, STMPE_INFO_MASK, + 0, 4, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 5, 0, STMPE_INFO_MASK, + 0, 5, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 6, 0, STMPE_INFO_MASK, + 0, 6, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 7, 0, STMPE_INFO_MASK, + 0, 7, IIO_ST('u', 12, 16, 0), STMPE_EV_M), +}; + +static const struct iio_chan_spec stmpe_adc_iio_channels[] = { + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 4, 0, STMPE_INFO_MASK, + 0, 4, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 5, 0, STMPE_INFO_MASK, + 0, 5, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 6, 0, STMPE_INFO_MASK, + 0, 6, IIO_ST('u', 12, 16, 0), STMPE_EV_M), + IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 7, 0, STMPE_INFO_MASK, + 0, 7, IIO_ST('u', 12, 16, 0), STMPE_EV_M), +}; + +static int stmpe_adc_remove_devices(struct device *dev, void *c) +{ + struct platform_device *pdev = to_platform_device(dev); + + platform_device_unregister(pdev); + + return 0; +} + +static int __devinit stmpe_adc_init_hw(struct stmpe_adc *adc) +{ + int ret; + u8 adc_ctrl1, adc_ctrl1_mask; + struct stmpe *stmpe = adc->stmpe; + struct device *dev = adc->dev; + + ret = stmpe_enable(stmpe, STMPE_BLOCK_ADC); + if (ret) { + dev_err(dev, "Could not enable clock for ADC\n"); + return ret; + } + + adc_ctrl1 = SAMPLE_TIME(adc->sample_time) | MOD_12B(adc->mod_12b) | + REF_SEL(adc->ref_sel); + adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff); + + ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1, + adc_ctrl1_mask, adc_ctrl1); + if (ret) { + dev_err(dev, "Could not setup ADC\n"); + return ret; + } + + ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2, + ADC_FREQ(0xff), ADC_FREQ(adc->adc_freq)); + if (ret) { + dev_err(dev, "Could not setup ADC\n"); + return ret; + } + + return 0; +} + + +static int __devinit stmpe_adc_probe(struct platform_device *pdev) +{ + struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); + struct stmpe_platform_data *pdata = stmpe->pdata; + struct stmpe_adc_platform_data *adc_pdata = NULL; + struct stmpe_adc *info = NULL; + struct iio_dev *indio_dev = NULL; + int ret = -ENODEV; + int irq; + + irq = platform_get_irq_byname(pdev, "STMPE_ADC"); + if (irq < 0) + return irq; + + indio_dev = iio_allocate_device(sizeof(struct stmpe_adc)); + if (!indio_dev) { + dev_err(&pdev->dev, "failed allocating iio device\n"); + return -ENOMEM; + } + + info = iio_priv(indio_dev); + info->irq = irq; + info->stmpe = stmpe; + + init_completion(&info->completion); + ret = request_threaded_irq(info->irq, NULL, stmpe_adc_isr, IRQF_ONESHOT, + "stmpe-adc", info); + if (ret < 0) { + dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", + info->irq); + goto err_free; + } + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &stmpe_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + /* Register TS-Channels only if they are available */ + if (stmpe->pdata->blocks & STMPE_BLOCK_TOUCHSCREEN) + indio_dev->channels = stmpe_adc_iio_channels; + else + indio_dev->channels = stmpe_adc_all_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(stmpe_adc_iio_channels); + + if (pdata) + adc_pdata = pdata->adc; + + if (adc_pdata) { + info->sample_time = adc_pdata->sample_time; + info->mod_12b = adc_pdata->mod_12b; + info->ref_sel = adc_pdata->ref_sel; + info->adc_freq = adc_pdata->adc_freq; + } + + ret = stmpe_adc_init_hw(info); + if (ret) + goto err_irq; + + ret = iio_device_register(indio_dev); + if (ret) + goto err_irq; + + + dev_info(&pdev->dev, "Initialized\n"); + + return 0; + +err_irq: + free_irq(info->irq, info); +err_free: + kfree(indio_dev); + return ret; +} + +static int stmpe_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct stmpe_adc *info = iio_priv(indio_dev); + + device_for_each_child(&pdev->dev, NULL, + stmpe_adc_remove_devices); + iio_device_unregister(indio_dev); + free_irq(info->irq, info); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int stmpe_adc_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct stmpe_adc *info = iio_priv(indio_dev); + + stmpe_adc_init_hw(info); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(stmpe_adc_pm_ops, NULL, stmpe_adc_resume); + +static struct platform_driver stmpe_adc_driver = { + .probe = stmpe_adc_probe, + .remove = stmpe_adc_remove, + .driver = { + .name = "stmpe-adc", + .owner = THIS_MODULE, + .pm = &stmpe_adc_pm_ops, + }, +}; + +module_platform_driver(stmpe_adc_driver); + +MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>"); +MODULE_DESCRIPTION("STMPEXXX ADC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:stmpe-adc"); diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index 19819e7578c6..fd812c343e81 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -860,7 +860,10 @@ static ssize_t iio_ev_state_show(struct device *dev, { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int val = indio_dev->info->read_event_config(indio_dev, + int val = -ENODEV; + + if (indio_dev->info != NULL && indio_dev->info->read_event_config != NULL) + val = indio_dev->info->read_event_config(indio_dev, this_attr->address); if (val < 0) @@ -875,9 +878,10 @@ static ssize_t iio_ev_value_show(struct device *dev, { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int val, ret; + int val, ret = -ENODEV; - ret = indio_dev->info->read_event_value(indio_dev, + if (indio_dev->info != NULL && indio_dev->info->read_event_config != NULL) + ret = indio_dev->info->read_event_value(indio_dev, this_attr->address, &val); if (ret < 0) return ret; diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index a3f966b39862..295fd2d7c713 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c @@ -1641,6 +1641,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) struct irq_info *i = dev_id; struct list_head *l, *end = NULL; int pass_counter = 0, handled = 0; + static unsigned int tegra_spurious = 0; DEBUG_INTR("serial8250_interrupt(%d)...", irq); @@ -1674,6 +1675,26 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) handled = 1; end = NULL; + } else if ((up->port.type == PORT_TEGRA) && !handled) { + /* irq 68: nobody cared workaround */ + + /* The irq request flag sometimes does not get reset or is + * asserted immediately, but iir does not indicated this, if + * so we get here with iir set to 0xc1, i.e. no irq pending. */ + + /* Try enabling the transmit register empty interrupt, + * iir becomes 0xc2, irq gets de-asserted and ier is reverted + * by the regular code flow in the ISR. */ + tegra_spurious++; + /* Try this every 4096 spurious irq. */ + if ((tegra_spurious % 0x1000) == 0xfff) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + udelay(1); + handled = 1; + end = NULL; + } else if (end == NULL) + end = l; } else if (end == NULL) end = l; diff --git a/drivers/tty/serial/tegra_hsuart.c b/drivers/tty/serial/tegra_hsuart.c index b2fa281492a7..3f38cca3d6ec 100644 --- a/drivers/tty/serial/tegra_hsuart.c +++ b/drivers/tty/serial/tegra_hsuart.c @@ -819,7 +819,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t) * Initialize the UART for a simple default configuration * so that the receive DMA buffer may be enqueued */ t->lcr_shadow = 3; /* no parity, stop, 8 data bits */ - tegra_set_baudrate(t, 115200); + tegra_set_baudrate(t, 9600); t->fcr_shadow |= UART_FCR_DMA_SELECT; uart_writeb(t, t->fcr_shadow, UART_FCR); if (tegra_start_dma_rx(t)) { diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 7b3185ff188a..9f79c267890e 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -399,8 +399,8 @@ static int rndis_function_bind_config(struct android_usb_function *f, rndis_control_intf.bInterfaceProtocol = 0x03; } - return rndis_bind_config(c, rndis->ethaddr, rndis->vendorID, - rndis->manufacturer); + return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID, + rndis->manufacturer); } static void rndis_function_unbind_config(struct android_usb_function *f, diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index f187b9eee9e5..25cb5fc8b263 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -774,9 +774,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); - if (rndis_set_param_vendor(rndis->config, rndis->vendorID, - rndis->manufacturer)) - goto fail; + if (rndis->manufacturer && rndis->vendorID && + rndis_set_param_vendor(rndis->config, rndis->vendorID, + rndis->manufacturer)) + goto fail; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -844,20 +845,8 @@ static inline bool can_support_rndis(struct usb_configuration *c) return true; } -/** - * rndis_bind_config - add RNDIS network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - * side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup(). Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], +rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], u32 vendorID, const char *manufacturer) { struct f_rndis *rndis; diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c index c130dae3a8e9..074a9b1ce6d9 100644 --- a/drivers/usb/gadget/tegra_udc.c +++ b/drivers/usb/gadget/tegra_udc.c @@ -52,8 +52,8 @@ #include "tegra_udc.h" -#define DRIVER_DESC "Nvidia Tegra High-Speed USB SOC \ - Device Controller driver" +#define DRIVER_DESC "Nvidia Tegra High-Speed USB SOC " \ + "Device Controller driver" #define DRIVER_AUTHOR "Venkat Moganty/Rakesh Bodla" #define DRIVER_VERSION "Apr 30, 2012" @@ -95,6 +95,11 @@ static const u8 tegra_udc_test_packet[53] = { 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e }; +#ifdef CONFIG_MACH_COLIBRI_T20 +/* To limit the speed of USB to full speed */ +extern int g_usb_high_speed; +#endif /* CONFIG_MACH_COLIBRI_T20 */ + static struct tegra_udc *the_udc; #ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ @@ -253,6 +258,16 @@ static int dr_controller_reset(struct tegra_udc *udc) cpu_relax(); } +#ifdef CONFIG_MACH_COLIBRI_T20 + /* To limit the speed of USB to full speed */ + if (!g_usb_high_speed) { + tmp = udc_readl(udc, PORTSCX_REG_OFFSET); + tmp |= PORTSCX_PORT_FORCE_FULL_SPEED; + udc_writel(udc, tmp, PORTSCX_REG_OFFSET); + tmp = udc_readl(udc, PORTSCX_REG_OFFSET); + } +#endif /* CONFIG_MACH_COLIBRI_T20 */ + DBG("%s(%d) END\n", __func__, __LINE__); return 0; } diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index 46772413f0db..c32227ebac0b 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -111,13 +111,13 @@ int eem_bind_config(struct usb_configuration *c); #ifdef USB_ETH_RNDIS -int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], +int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], u32 vendorID, const char *manufacturer); #else static inline int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], +rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], u32 vendorID, const char *manufacturer) { return 0; @@ -125,4 +125,23 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], #endif +/** + * rndis_bind_config - add RNDIS network link to a configuration + * @c: the configuration to support the network link + * @ethaddr: a buffer in which the ethernet address of the host side + * side of the link was recorded + * Context: single threaded during gadget setup + * + * Returns zero on success, else negative errno. + * + * Caller must have called @gether_setup(). Caller is also responsible + * for calling @gether_cleanup() before module unload. + */ +static inline int rndis_bind_config(struct usb_configuration *c, + u8 ethaddr[ETH_ALEN]) +{ + return rndis_bind_config_vendor(c, ethaddr, 0, NULL); +} + + #endif /* __U_ETHER_H */ diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 4ddb279cfb35..095447d9e3a2 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -23,12 +23,16 @@ #include <mach/usb_phy.h> #include <mach/iomap.h> +#include "../../../arch/arm/mach-tegra/tegra_usb_phy.h" + #if 0 #define EHCI_DBG(stuff...) pr_info("ehci-tegra: " stuff) #else #define EHCI_DBG(stuff...) do {} while (0) #endif +#define TEGRA_USB_PORTSC1_PFSC (1 << 24) + static const char driver_name[] = "tegra-ehci"; #define TEGRA_USB_DMA_ALIGN 32 @@ -51,6 +55,22 @@ struct dma_align_buffer { u8 data[0]; }; +#ifdef CONFIG_MACH_COLIBRI_T20 +/* To limit the speed of USB to full speed */ +int g_usb_high_speed = 0; + +/* To limit the speed of USB to full speed */ +static int __init enable_usb_high_speed(char *s) +{ + if (!(*s) || !strcmp(s, "1")) + g_usb_high_speed = 1; + + return 0; +} +__setup("usb_high_speed=", enable_usb_high_speed); +EXPORT_SYMBOL_GPL(g_usb_high_speed); +#endif /* CONFIG_MACH_COLIBRI_T20 */ + static void free_align_buffer(struct urb *urb) { struct dma_align_buffer *temp = container_of(urb->transfer_buffer, @@ -186,6 +206,71 @@ static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd) return irq_status; } +static int tegra_ehci_internal_port_reset( + struct ehci_hcd *ehci, + u32 __iomem *portsc_reg +) +{ + u32 temp; + unsigned long flags; + int retval = 0; + int i, tries; + u32 saved_usbintr; + + spin_lock_irqsave(&ehci->lock, flags); + saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable); + /* disable USB interrupt */ + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + spin_unlock_irqrestore(&ehci->lock, flags); + + /* + * Here we have to do Port Reset at most twice for + * Port Enable bit to be set. + */ + for (i = 0; i < 2; i++) { + temp = ehci_readl(ehci, portsc_reg); + temp |= PORT_RESET; + ehci_writel(ehci, temp, portsc_reg); + mdelay(10); + temp &= ~PORT_RESET; + ehci_writel(ehci, temp, portsc_reg); + mdelay(1); + tries = 100; + do { + mdelay(1); + /* + * Up to this point, Port Enable bit is + * expected to be set after 2 ms waiting. + * USB1 usually takes extra 45 ms, for safety, + * we take 100 ms as timeout. + */ + temp = ehci_readl(ehci, portsc_reg); + } while (!(temp & PORT_PE) && tries--); + if (temp & PORT_PE) + break; + } + if (i == 2) + retval = -ETIMEDOUT; + + /* + * Clear Connect Status Change bit if it's set. + * We can't clear PORT_PEC. It will also cause PORT_PE to be cleared. + */ + if (temp & PORT_CSC) + ehci_writel(ehci, PORT_CSC, portsc_reg); + + /* + * Write to clear any interrupt status bits that might be set + * during port reset. + */ + temp = ehci_readl(ehci, &ehci->regs->status); + ehci_writel(ehci, temp, &ehci->regs->status); + + /* restore original interrupt enable bits */ + ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable); + + return retval; +} static int tegra_ehci_hub_control( struct usb_hcd *hcd, @@ -201,6 +286,29 @@ static int tegra_ehci_hub_control( int retval = 0; u32 __iomem *status_reg; +#ifdef CONFIG_MACH_COLIBRI_T20 + u32 temp; + + /* To limit the speed of USB to full speed */ + if (!g_usb_high_speed) { + /* Check whether port is not 2nd one internally connected to + ASIX Ethernet chip, set PFSC (Port Force Full Speed) only + for externally accessible OTG and host port */ + if (tegra->phy->inst != 1) { + status_reg = &ehci->regs->port_status[(wIndex & 0xff) + - 1]; + temp = ehci_readl(ehci, status_reg); + /* Check whether PFSC bit is already set or not */ + if (!(temp & TEGRA_USB_PORTSC1_PFSC)) { + ehci_writel(ehci, (temp | + TEGRA_USB_PORTSC1_PFSC), + status_reg); + temp = ehci_readl(ehci, status_reg); + } + } + } +#endif /* CONFIG_MACH_COLIBRI_T20 */ + if (!tegra_usb_phy_hw_accessible(tegra->phy)) { if (buf) memset(buf, 0, wLength); @@ -249,6 +357,13 @@ static int tegra_ehci_hub_control( break; } + /* For USB1 port we need to issue Port Reset twice internally */ + if (tegra->phy->inst == 0 && + (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { + status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; + return tegra_ehci_internal_port_reset(ehci, status_reg); + } + /* handle ehci hub control request */ retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index bcb3e8680337..e38d2b4ca134 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -25,6 +25,14 @@ if USB || USB_GADGET # # USB Transceiver Drivers # +config USB_COLIBRI_OTG + boolean "Colibri OTG Driver" + depends on USB && ARCH_TEGRA && !USB_TEGRA_OTG + select USB_OTG_UTILS + help + Enable this driver on boards which use a regular GPIO for VBUS + detection. + config USB_GPIO_VBUS tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" depends on GENERIC_GPIO diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 0ef95e45a583..cbedff4e254f 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg_id.o # transceiver drivers obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o +obj-$(CONFIG_USB_COLIBRI_OTG) += colibri-otg.o CFLAGS_tegra-otg.o = -Werror obj-$(CONFIG_USB_TEGRA_OTG) += tegra-otg.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o diff --git a/drivers/usb/otg/colibri-otg.c b/drivers/usb/otg/colibri-otg.c new file mode 100644 index 000000000000..54d792536363 --- /dev/null +++ b/drivers/usb/otg/colibri-otg.c @@ -0,0 +1,268 @@ +/* + * drivers/usb/otg/colibri-otg.c + * + * OTG transceiver driver for Tegra UTMI phy with GPIO VBUS detection + * + * Copyright (C) 2010 NVIDIA Corp. + * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2012 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/colibri_usb.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/gadget.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include <mach/gpio.h> + +struct colibri_otg_data { + struct otg_transceiver otg; + spinlock_t lock; + int irq; + struct platform_device *host; + struct platform_device *pdev; + struct work_struct work; +}; + +static const char *tegra_state_name(enum usb_otg_state state) +{ + if (state == OTG_STATE_A_HOST) + return "HOST"; + if (state == OTG_STATE_B_PERIPHERAL) + return "PERIPHERAL"; + if (state == OTG_STATE_A_SUSPEND) + return "SUSPEND"; + return "INVALID"; +} + +void tegra_start_host(struct colibri_otg_data *tegra) +{ + struct colibri_otg_platform_data *pdata = tegra->otg.dev->platform_data; + if (!tegra->pdev) { + tegra->pdev = pdata->host_register(); + } +} + +void tegra_stop_host(struct colibri_otg_data *tegra) +{ + struct colibri_otg_platform_data *pdata = tegra->otg.dev->platform_data; + if (tegra->pdev) { + pdata->host_unregister(tegra->pdev); + tegra->pdev = NULL; + } +} + +static void tegra_otg_notify_event(struct otg_transceiver *otg, + enum usb_xceiv_events event) +{ + otg->last_event = event; + atomic_notifier_call_chain(&otg->notifier, event, NULL); +} + +static void irq_work(struct work_struct *work) +{ + struct colibri_otg_data *tegra = + container_of(work, struct colibri_otg_data, work); + struct otg_transceiver *otg = &tegra->otg; + enum usb_otg_state from = otg->state; + enum usb_otg_state to = OTG_STATE_UNDEFINED; + unsigned long flags; + + spin_lock_irqsave(&tegra->lock, flags); + + /* Check client detect (High active) */ + mdelay(100); + if (gpio_get_value(irq_to_gpio(tegra->irq))) + to = OTG_STATE_B_PERIPHERAL; + else + to = OTG_STATE_A_HOST; + + spin_unlock_irqrestore(&tegra->lock, flags); + + if (to != OTG_STATE_UNDEFINED) { + otg->state = to; + + if (from != to) { + dev_info(tegra->otg.dev, "%s --> %s\n", + tegra_state_name(from), tegra_state_name(to)); + + if (to == OTG_STATE_B_PERIPHERAL) { + if (from == OTG_STATE_A_HOST) { + tegra_stop_host(tegra); + tegra_otg_notify_event(otg, USB_EVENT_NONE); + } + if (otg->gadget) { + usb_gadget_vbus_connect(otg->gadget); + tegra_otg_notify_event(otg, USB_EVENT_VBUS); + } + } else if (to == OTG_STATE_A_HOST) { + if (otg->gadget && (from == OTG_STATE_B_PERIPHERAL)) { + usb_gadget_vbus_disconnect(otg->gadget); + tegra_otg_notify_event(otg, USB_EVENT_NONE); + } + tegra_start_host(tegra); + tegra_otg_notify_event(otg, USB_EVENT_ID); + } + } + } +} + +static irqreturn_t colibri_otg_irq(int irq, void *data) +{ + struct colibri_otg_data *tegra = data; + + schedule_work(&tegra->work); + + return IRQ_HANDLED; +} + +static int colibri_otg_set_peripheral(struct otg_transceiver *otg, + struct usb_gadget *gadget) +{ + struct colibri_otg_data *tegra; + + tegra = container_of(otg, struct colibri_otg_data, otg); + otg->gadget = gadget; + + /* Set initial state */ + schedule_work(&tegra->work); + + return 0; +} + +static int colibri_otg_set_host(struct otg_transceiver *otg, + struct usb_bus *host) +{ + struct colibri_otg_data *tegra; + + tegra = container_of(otg, struct colibri_otg_data, otg); + otg->host = host; + + return 0; +} + +static int colibri_otg_set_power(struct otg_transceiver *otg, unsigned mA) +{ + return 0; +} + +static int colibri_otg_set_suspend(struct otg_transceiver *otg, int suspend) +{ + return 0; +} + +static int colibri_otg_probe(struct platform_device *pdev) +{ + struct colibri_otg_data *tegra; + struct colibri_otg_platform_data *plat = pdev->dev.platform_data; + int err, gpio_cd; + + if (!plat) { + dev_err(&pdev->dev, "no platform data?\n"); + return -ENODEV; + } + + tegra = kzalloc(sizeof(struct colibri_otg_data), GFP_KERNEL); + if (!tegra) + return -ENOMEM; + + tegra->otg.dev = &pdev->dev; + tegra->otg.label = "colibri-otg"; + tegra->otg.state = OTG_STATE_UNDEFINED; + tegra->otg.set_host = colibri_otg_set_host; + tegra->otg.set_peripheral = colibri_otg_set_peripheral; + tegra->otg.set_suspend = colibri_otg_set_suspend; + tegra->otg.set_power = colibri_otg_set_power; + spin_lock_init(&tegra->lock); + + platform_set_drvdata(pdev, tegra); + + tegra->otg.state = OTG_STATE_A_SUSPEND; + + err = otg_set_transceiver(&tegra->otg); + if (err) { + dev_err(&pdev->dev, "can't register transceiver (%d)\n", err); + goto err_otg; + } + + gpio_cd = plat->cable_detect_gpio; + err = gpio_request(gpio_cd, "USBC_DET"); + if (err) + goto err_gpio; + gpio_direction_input(gpio_cd); + + tegra->irq = gpio_to_irq(gpio_cd); + err = request_threaded_irq(tegra->irq, colibri_otg_irq, NULL, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "colibri-otg USBC_DET", tegra); + if (err) { + dev_err(&pdev->dev, "Failed to register USB client detect IRQ\n"); + goto err_irq; + } + + INIT_WORK (&tegra->work, irq_work); + + dev_info(&pdev->dev, "otg transceiver registered\n"); + + return 0; + +err_irq: + gpio_free(gpio_cd); +err_gpio: + otg_set_transceiver(NULL); +err_otg: + platform_set_drvdata(pdev, NULL); + kfree(tegra); + return err; +} + +static int __exit colibri_otg_remove(struct platform_device *pdev) +{ + struct colibri_otg_data *tegra = platform_get_drvdata(pdev); + + free_irq(tegra->irq, tegra); + gpio_free(irq_to_gpio(tegra->irq)); + otg_set_transceiver(NULL); + platform_set_drvdata(pdev, NULL); + kfree(tegra); + + return 0; +} + +static struct platform_driver colibri_otg_driver = { + .driver = { + .name = "colibri-otg", + }, + .remove = __exit_p(colibri_otg_remove), + .probe = colibri_otg_probe, +}; + +static int __init colibri_otg_init(void) +{ + return platform_driver_register(&colibri_otg_driver); +} +subsys_initcall(colibri_otg_init); + +static void __exit colibri_otg_exit(void) +{ + platform_driver_unregister(&colibri_otg_driver); +} +module_exit(colibri_otg_exit); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 2a9ed6ec8cb7..ea4e5ebdd35a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -231,9 +231,11 @@ static void option_instat_callback(struct urb *urb); #define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000 #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 +#define NOVATELWIRELESS_PRODUCT_E362 0x9010 #define NOVATELWIRELESS_PRODUCT_G1 0xA001 #define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 #define NOVATELWIRELESS_PRODUCT_G2 0xA010 +#define NOVATELWIRELESS_PRODUCT_MC551 0xB001 /* AMOI PRODUCTS */ #define AMOI_VENDOR_ID 0x1614 @@ -265,6 +267,9 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181 #define DELL_PRODUCT_5730_MINICARD_VZW 0x8182 +#define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */ +#define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */ + #define KYOCERA_VENDOR_ID 0x0c88 #define KYOCERA_PRODUCT_KPC650 0x17da #define KYOCERA_PRODUCT_KPC680 0x180a @@ -715,6 +720,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) }, + /* Novatel Ovation MC551 a.k.a. Verizon USB551L */ + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, @@ -737,6 +745,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_SPRINT) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_TELUS) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 39ac49e0682c..7fce1987ddc7 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -82,4 +82,8 @@ config LOGO_M32R_CLUT224 depends on M32R default y +config LOGO_CUSTOM_CLUT224 + bool "Custom 224-color Linux logo" + default n + endif # LOGO diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index 3b437813584c..45d4b5346d07 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -18,6 +18,8 @@ obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o obj-$(CONFIG_SPU_BASE) += logo_spe_clut224.o +obj-$(CONFIG_LOGO_CUSTOM_CLUT224) += logo_custom_clut224.o + # How to generate logo's # Use logo-cfiles to retrieve list of .c files to be built diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index ea7a8ccc830c..6e29415c9790 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -100,6 +100,10 @@ const struct linux_logo * __init_refok fb_find_logo(int depth) /* M32R Linux logo */ logo = &logo_m32r_clut224; #endif +#ifdef CONFIG_LOGO_CUSTOM_CLUT224 + /* Custom Linux logo */ + logo = &logo_custom_clut224; +#endif } return logo; } diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index bfd916e0e16e..d4c3f8bc9a49 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -1067,9 +1067,11 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status) queue_work(system_freezable_wq, &dc->vblank_work); if (status & FRAME_END_INT) { +#ifndef CONFIG_ANDROID struct timespec tm = CURRENT_TIME; dc->frame_end_timestamp = timespec_to_ns(&tm); wake_up(&dc->timestamp_wq); +#endif /* !CONFIG_ANDROID */ /* Mark the frame_end as complete. */ if (!completion_done(&dc->frame_end_complete)) @@ -1079,6 +1081,7 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status) } } +#ifndef CONFIG_ANDROID /* XXX: Not sure if we limit look ahead to 1 frame */ bool tegra_dc_is_within_n_vsync(struct tegra_dc *dc, s64 ts) { @@ -1094,6 +1097,7 @@ bool tegra_dc_does_vsync_separate(struct tegra_dc *dc, s64 new_ts, s64 old_ts) != div_s64((old_ts - dc->frame_end_timestamp), dc->frametime_ns))); } +#endif /* !CONFIG_ANDROID */ #endif static irqreturn_t tegra_dc_irq(int irq, void *ptr) @@ -1781,7 +1785,9 @@ static int tegra_dc_probe(struct nvhost_device *ndev, mutex_init(&dc->one_shot_lock); init_completion(&dc->frame_end_complete); init_waitqueue_head(&dc->wq); +#ifndef CONFIG_ANDROID init_waitqueue_head(&dc->timestamp_wq); +#endif /* !CONFIG_ANDROID */ #ifdef CONFIG_ARCH_TEGRA_2x_SOC INIT_WORK(&dc->reset_work, tegra_dc_reset_worker); #endif diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h index 75c3a2a29658..e91071f70ddc 100644 --- a/drivers/video/tegra/dc/dc_priv.h +++ b/drivers/video/tegra/dc/dc_priv.h @@ -113,14 +113,18 @@ struct tegra_dc { void *out_data; struct tegra_dc_mode mode; +#ifndef CONFIG_ANDROID s64 frametime_ns; +#endif /* !CONFIG_ANDROID */ struct tegra_dc_win windows[DC_N_WINDOWS]; struct tegra_dc_blend blend; int n_windows; wait_queue_head_t wq; +#ifndef CONFIG_ANDROID wait_queue_head_t timestamp_wq; +#endif /* !CONFIG_ANDROID */ struct mutex lock; struct mutex one_shot_lock; @@ -165,7 +169,9 @@ struct tegra_dc { struct delayed_work underflow_work; u32 one_shot_delay_ms; struct delayed_work one_shot_work; +#ifndef CONFIG_ANDROID s64 frame_end_timestamp; +#endif /* !CONFIG_ANDROID */ }; #define print_mode_info(dc, mode) do { \ diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c index 88273e26c51c..37a6d9bd3f80 100644 --- a/drivers/video/tegra/dc/ext/dev.c +++ b/drivers/video/tegra/dc/ext/dev.c @@ -56,7 +56,9 @@ struct tegra_dc_ext_flip_data { struct tegra_dc_ext *ext; struct work_struct work; struct tegra_dc_ext_flip_win win[DC_N_WINDOWS]; +#ifndef CONFIG_ANDROID struct list_head timestamp_node; +#endif /* !CONFIG_ANDROID */ }; int tegra_dc_ext_get_num_outputs(void) @@ -208,7 +210,9 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext, { int err = 0; struct tegra_dc_ext_win *ext_win = &ext->win[win->idx]; +#ifndef CONFIG_ANDROID s64 timestamp_ns; +#endif /* !CONFIG_ANDROID */ if (flip_win->handle[TEGRA_DC_Y] == NULL) { win->flags = 0; @@ -272,6 +276,7 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext, msecs_to_jiffies(500), NULL); } +#ifndef CONFIG_ANDROID #ifndef CONFIG_TEGRA_SIMULATION_PLATFORM timestamp_ns = timespec_to_ns(&flip_win->attr.timestamp); @@ -286,9 +291,12 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext, } #endif return err; +#else /* !CONFIG_ANDROID */ + return 0; +#endif /* !CONFIG_ANDROID */ } -static void (*flip_callback)(void); +static int (*flip_callback)(void); static spinlock_t flip_callback_lock; static bool init_tegra_dc_flip_callback_called; @@ -301,7 +309,7 @@ static int __init init_tegra_dc_flip_callback(void) pure_initcall(init_tegra_dc_flip_callback); -int tegra_dc_set_flip_callback(void (*callback)(void)) +int tegra_dc_set_flip_callback(int (*callback)(void)) { WARN_ON(!init_tegra_dc_flip_callback_called); @@ -337,11 +345,14 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; - int j = 0, index = flip_win->attr.index; + int index = flip_win->attr.index; struct tegra_dc_win *win; struct tegra_dc_ext_win *ext_win; +#ifndef CONFIG_ANDROID + int j = 0; struct tegra_dc_ext_flip_data *temp = NULL; s64 head_timestamp = 0; +#endif /* !CONFIG_ANDROID */ if (index < 0) continue; @@ -353,6 +364,7 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR)) skip_flip = true; +#ifndef CONFIG_ANDROID mutex_lock(&ext_win->queue_lock); list_for_each_entry(temp, &ext_win->timestamp_queue, timestamp_node) { @@ -377,6 +389,7 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) if (!list_empty(&ext_win->timestamp_queue)) list_del(&data->timestamp_node); mutex_unlock(&ext_win->queue_lock); +#endif /* !CONFIG_ANDROID */ if (win->flags & TEGRA_WIN_FLAG_ENABLED) { int j; @@ -409,6 +422,9 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) flip_callback(); spin_unlock(&flip_callback_lock); } +#ifdef CONFIG_ANDROID + } +#endif /* CONFIG_ANDROID */ for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; @@ -420,7 +436,9 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) tegra_dc_incr_syncpt_min(ext->dc, index, flip_win->syncpt_max); } +#ifndef CONFIG_ANDROID } +#endif /* !CONFIG_ANDROID */ /* unpin and deref previous front buffers */ for (i = 0; i < nr_unpin; i++) { @@ -531,7 +549,9 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user, struct tegra_dc_ext_flip_data *data; int work_index = -1; int i, ret = 0; +#ifndef CONFIG_ANDROID bool has_timestamp = false; +#endif /* !CONFIG_ANDROID */ #ifdef CONFIG_ANDROID int index_check[DC_N_WINDOWS] = {0, }; @@ -572,8 +592,10 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user, int index = args->win[i].index; memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr)); +#ifndef CONFIG_ANDROID if (timespec_to_ns(&flip_win->attr.timestamp)) has_timestamp = true; +#endif /* !CONFIG_ANDROID */ if (index < 0) continue; @@ -648,11 +670,13 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user, ret = -EINVAL; goto unlock; } +#ifndef CONFIG_ANDROID if (has_timestamp) { mutex_lock(&ext->win[work_index].queue_lock); list_add_tail(&data->timestamp_node, &ext->win[work_index].timestamp_queue); mutex_unlock(&ext->win[work_index].queue_lock); } +#endif /* !CONFIG_ANDROID */ queue_work(ext->win[work_index].flip_wq, &data->work); unlock_windows_for_flip(user, args); @@ -993,8 +1017,10 @@ static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext) } mutex_init(&win->lock); +#ifndef CONFIG_ANDROID mutex_init(&win->queue_lock); INIT_LIST_HEAD(&win->timestamp_queue); +#endif /* !CONFIG_ANDROID */ } return 0; diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h index ef7361d1d933..7238e95e59db 100644 --- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h +++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h @@ -59,9 +59,11 @@ struct tegra_dc_ext_win { atomic_t nr_pending_flips; +#ifndef CONFIG_ANDROID struct mutex queue_lock; struct list_head timestamp_queue; +#endif /* !CONFIG_ANDROID */ }; struct tegra_dc_ext { diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c index 55d9163d4faf..225d48ab15ee 100644 --- a/drivers/video/tegra/dc/hdmi.c +++ b/drivers/video/tegra/dc/hdmi.c @@ -1258,6 +1258,9 @@ static bool tegra_dc_hdmi_valid_asp_ratio(const struct tegra_dc *dc, int m_aspratio = 0; int s_aspratio = 0; + if (!mode->yres) + return false; + /* To check the aspect upto two decimal digits, calculate in % */ m_aspratio = (mode->xres*100 / mode->yres); @@ -1345,7 +1348,8 @@ void tegra_dc_hdmi_detect_config(struct tegra_dc *dc, hdmi->dvi = !(specs->misc & FB_MISC_HDMI); - tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter); + if (dc->fb != NULL) + tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter); #ifdef CONFIG_SWITCH hdmi->hpd_switch.state = 0; switch_set_state(&hdmi->hpd_switch, 1); @@ -1413,11 +1417,18 @@ static bool tegra_dc_hdmi_detect(struct tegra_dc *dc) struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); struct fb_monspecs specs; int err; + int cnt = 0; if (!tegra_dc_hdmi_hpd(dc)) goto fail; err = tegra_edid_get_monspecs(hdmi->edid, &specs); + /* retry, maybe hdmi detect is not debounced or the monitor needs some time */ + while ( (err < 0) && (cnt++ < 4) ) { + dev_err(&dc->ndev->dev, "error reading edid, trying again in 500ms\n"); + msleep(500); + err = tegra_edid_get_monspecs(hdmi->edid, &specs); + } if (err < 0) { if (dc->out->n_modes) tegra_dc_enable(dc); diff --git a/drivers/video/tegra/dc/mode.c b/drivers/video/tegra/dc/mode.c index 3a95f2e7ab0e..f5cd4fb0cdea 100644 --- a/drivers/video/tegra/dc/mode.c +++ b/drivers/video/tegra/dc/mode.c @@ -26,6 +26,179 @@ #include "dc_reg.h" #include "dc_priv.h" +const struct fb_videomode tegra_modes[] = { + /* EDT 5.7" ET070080DH or TouchRevolution Fusion 7" */ + { + .name = "800x480", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = 30807, + .left_margin = 128, + .right_margin = 64, + .upper_margin = 22, + .lower_margin = 20, + .hsync_len = 64, + .vsync_len = 3, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .flag = FB_FLAG_RATIO_16_9, + .vmode = FB_VMODE_NONINTERLACED + }, + /* TouchRevolution Fusion 10" aka Chunghwa Picture Tubes + * CLAA100NC05 10.1 inch 1024x600 single channel LVDS panel + */ + { + .name = "1024x600", + .refresh = 60, + .xres = 1024, + .yres = 600, + .pixclock = KHZ2PICOS(48000), + .left_margin = 104, + .right_margin = 43, + .upper_margin = 24, + .lower_margin = 20, + .hsync_len = 5, + .vsync_len = 5, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .flag = FB_FLAG_RATIO_16_9, + .vmode = FB_VMODE_NONINTERLACED + }, + { + /* 1366x768 */ + .refresh = 60, + .xres = 1366, + .yres = 768, + .pixclock = KHZ2PICOS(72072), + .hsync_len = 58, /* h_sync_width */ + .vsync_len = 4, /* v_sync_width */ + .left_margin = 58, /* h_back_porch */ + .upper_margin = 4, /* v_back_porch */ + .right_margin = 58, /* h_front_porch */ + .lower_margin = 4, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + { + /* 1680x1050p 59.94/60hz */ + .refresh = 60, + .xres = 1680, + .yres = 1050, + .pixclock = KHZ2PICOS(147140), + .hsync_len = 184, /* h_sync_width */ + .vsync_len = 3, /* v_sync_width */ + .left_margin = 288, /* h_back_porch */ + .upper_margin = 33, /* v_back_porch */ + .right_margin = 104, /* h_front_porch */ + .lower_margin = 1, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + { + /* 1920x1080p 59.94/60hz CVT */ + .refresh = 60, + .xres = 1920, + .yres = 1080, + .pixclock = KHZ2PICOS(148500), + .hsync_len = 44, /* h_sync_width */ + .vsync_len = 5, /* v_sync_width */ + .left_margin = 148, /* h_back_porch */ + .upper_margin = 36, /* v_back_porch */ + .right_margin = 88, /* h_front_porch */ + .lower_margin = 4, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + { + /* 1920x1200p 60hz */ + .refresh = 60, + .xres = 1920, + .yres = 1200, + .pixclock = KHZ2PICOS(154000), + .hsync_len = 32, /* h_sync_width */ + .vsync_len = 6, /* v_sync_width */ + .left_margin = 80, /* h_back_porch */ + .upper_margin = 26, /* v_back_porch */ + .right_margin = 48, /* h_front_porch */ + .lower_margin = 3, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = 0, + }, + /* Portrait modes */ + { + .name = "480x640", + .refresh = 60, + .xres = 480, + .yres = 640, + .pixclock = 55555, + .left_margin = 20, + .right_margin = 8, + .upper_margin = 7, + .lower_margin = 8, + .hsync_len = 4, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "540x960", + .refresh = 60, + .xres = 540, + .yres = 960, + .pixclock = 100000, + .left_margin = 32, + .right_margin = 32, + .upper_margin = 1, + .lower_margin = 2, + .hsync_len = 16, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "720x1280", + .refresh = 60, + .xres = 720, + .yres = 1280, + .pixclock = 16282, + .left_margin = 100, + .right_margin = 4, + .upper_margin = 14, + .lower_margin = 4, + .hsync_len = 4, + .vsync_len = 4, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, +}; + +/* try to find best matching mode using our modes, VESA and CEA modes from + * modedb + */ +int tegra_fb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, + const char* option, unsigned int default_bpp) +{ + int out; + + out = fb_find_mode(var, info, option, tegra_modes, + ARRAY_SIZE(tegra_modes), NULL, default_bpp); + + /* Only accept this mode if we found a reasonable match (resolution) */ + if (out == 1 || out == 2) + return out; + + out = fb_find_mode(&info->var, info, option, + cea_modes, CEA_MODEDB_SIZE, NULL, default_bpp); + + /* Check if we found a full match */ + if (out == 1 || out == 2) + return out; + + return fb_find_mode(&info->var, info, option, + vesa_modes, VESA_MODEDB_SIZE, NULL, default_bpp); +} +EXPORT_SYMBOL(tegra_fb_find_mode); + + /* return non-zero if constraint is violated */ static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href) { @@ -137,6 +310,7 @@ static bool check_ref_to_sync(struct tegra_dc_mode *mode) return true; } +#ifndef CONFIG_ANDROID static s64 calc_frametime_ns(const struct tegra_dc_mode *m) { long h_total, v_total; @@ -147,6 +321,7 @@ static s64 calc_frametime_ns(const struct tegra_dc_mode *m) return (!m->pclk) ? 0 : (s64)(div_s64(((s64)h_total * v_total * 1000000000ULL), m->pclk)); } +#endif /* !CONFIG_ANDROID */ /* return in 1000ths of a Hertz */ int tegra_dc_calc_refresh(const struct tegra_dc_mode *m) @@ -270,21 +445,108 @@ int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode) { memcpy(&dc->mode, mode, sizeof(dc->mode)); + dev_info(&dc->ndev->dev, "using mode %dx%d pclk=%d href=%d vref=%d\n", + mode->h_active, mode->v_active, mode->pclk, + mode->h_ref_to_sync, mode->v_ref_to_sync + ); + if (dc->out->type == TEGRA_DC_OUT_RGB) panel_sync_rate = tegra_dc_calc_refresh(mode); else if (dc->out->type == TEGRA_DC_OUT_DSI) panel_sync_rate = dc->out->dsi->rated_refresh_rate * 1000; print_mode(dc, mode, __func__); +#ifndef CONFIG_ANDROID dc->frametime_ns = calc_frametime_ns(mode); +#endif /* !CONFIG_ANDROID */ return 0; } EXPORT_SYMBOL(tegra_dc_set_mode); +int tegra_dc_var_to_dc_mode(struct tegra_dc *dc, struct fb_var_screeninfo *var, + struct tegra_dc_mode *mode) +{ + bool stereo_mode = false; + int err; + + if (!var->pixclock) + return -EINVAL; + + mode->pclk = PICOS2KHZ(var->pixclock) * 1000; + mode->h_sync_width = var->hsync_len; + mode->v_sync_width = var->vsync_len; + mode->h_back_porch = var->left_margin; + mode->v_back_porch = var->upper_margin; + mode->h_active = var->xres; + mode->v_active = var->yres; + mode->h_front_porch = var->right_margin; + mode->v_front_porch = var->lower_margin; + mode->stereo_mode = stereo_mode; + + /* + * HACK: + * If v_front_porch is only 1, we would violate Constraint 5/6 + * in this case, increase front porch by 1 + */ + if (mode->v_front_porch <= 1) + mode->v_front_porch = 2; + + + if (dc->out->type == TEGRA_DC_OUT_HDMI) { + /* HDMI controller requires h_ref=1, v_ref=1 */ + mode->h_ref_to_sync = 1; + mode->v_ref_to_sync = 1; + } else { + /* Calculate ref_to_sync signals */ + err = calc_ref_to_sync(mode); + if (err) { + dev_err(&dc->ndev->dev, "display timing ref_to_sync" + "calculation failed with code %d\n", err); + return -EINVAL; + } + dev_info(&dc->ndev->dev, "Calculated sync href=%d vref=%d\n", + mode->h_ref_to_sync, mode->v_ref_to_sync); + } + if (!check_ref_to_sync(mode)) { + dev_err(&dc->ndev->dev, + "display timing doesn't meet restrictions.\n"); + return -EINVAL; + } + +#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT + /* Double the pixel clock and update v_active only for + * frame packed mode */ + if (mode->stereo_mode) { + mode->pclk *= 2; + /* total v_active = yres*2 + activespace */ + mode->v_active = var->yres * 2 + + var->vsync_len + + var->upper_margin + + var->lower_margin; + } +#endif + + mode->flags = 0; + + if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) + mode->flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC; + + if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) + mode->flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC; + + return 0; +} +EXPORT_SYMBOL(tegra_dc_var_to_dc_mode); + +/* + * This method is only used by sysfs interface + * /sys/devices/tegradc.1/nvdps + */ int tegra_dc_set_fb_mode(struct tegra_dc *dc, const struct fb_videomode *fbmode, bool stereo_mode) { + int err; struct tegra_dc_mode mode; if (!fbmode->pixclock) @@ -305,17 +567,28 @@ int tegra_dc_set_fb_mode(struct tegra_dc *dc, mode.h_ref_to_sync = 1; mode.v_ref_to_sync = 1; } else { - calc_ref_to_sync(&mode); + /* + * HACK: + * If v_front_porch is only 1, we would violate Constraint 5/6 + * in this case, increase front porch by 1 + */ + if (mode.v_front_porch <= 1) + mode.v_front_porch = 2; + + err = calc_ref_to_sync(&mode); + if (err) { + dev_err(&dc->ndev->dev, "display timing ref_to_sync" + "calculation failed with code %d\n", err); + return -EINVAL; + } + dev_info(&dc->ndev->dev, "Calculated sync href=%d vref=%d\n", + mode.h_ref_to_sync, mode.v_ref_to_sync); } if (!check_ref_to_sync(&mode)) { dev_err(&dc->ndev->dev, - "Display timing doesn't meet restrictions.\n"); + "display timing doesn't meet restrictions.\n"); return -EINVAL; } - dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n", - mode.h_active, mode.v_active, mode.pclk, - mode.h_ref_to_sync, mode.v_ref_to_sync - ); #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT /* Double the pixel clock and update v_active only for diff --git a/drivers/video/tegra/dc/nvhdcp.c b/drivers/video/tegra/dc/nvhdcp.c index 3566e2bd33b5..8489ebf69719 100644 --- a/drivers/video/tegra/dc/nvhdcp.c +++ b/drivers/video/tegra/dc/nvhdcp.c @@ -760,7 +760,7 @@ static int get_repeater_info(struct tegra_nvhdcp *nvhdcp) { int e, retries; u8 b_caps; - u16 b_status; + u16 b_status = 0; nvhdcp_vdbg("repeater found:fetching repeater info\n"); diff --git a/drivers/video/tegra/dc/window.c b/drivers/video/tegra/dc/window.c index cd91fab428ed..af18564f45b9 100644 --- a/drivers/video/tegra/dc/window.c +++ b/drivers/video/tegra/dc/window.c @@ -24,7 +24,9 @@ #include "dc_priv.h" static int no_vsync; +#ifndef CONFIG_ANDROID static atomic_t frame_end_ref = ATOMIC_INIT(0); +#endif /* !CONFIG_ANDROID */ module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR); @@ -41,6 +43,7 @@ static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[], return true; } +#ifndef CONFIG_ANDROID int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable) { tegra_dc_writel(dc, FRAME_END_INT, DC_CMD_INT_STATUS); @@ -51,6 +54,7 @@ int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable) tegra_dc_mask_interrupt(dc, FRAME_END_INT); return 0; } +#endif /* !CONFIG_ANDROID */ static int get_topmost_window(u32 *depths, unsigned long *wins) { @@ -418,9 +422,14 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); } else { clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count); - tegra_dc_mask_interrupt(dc, V_BLANK_INT | ALL_UF_INT); + tegra_dc_mask_interrupt(dc, +#ifndef CONFIG_ANDROID + V_BLANK_INT | ALL_UF_INT); if (!atomic_read(&frame_end_ref)) tegra_dc_mask_interrupt(dc, FRAME_END_INT); +#else /* !CONFIG_ANDROID */ + FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); +#endif /* !CONFIG_ANDROID */ } if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) @@ -470,7 +479,11 @@ void tegra_dc_trigger_windows(struct tegra_dc *dc) if (!dirty) { if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) +#ifndef CONFIG_ANDROID && !atomic_read(&frame_end_ref)) +#else /* !CONFIG_ANDROID */ + ) +#endif /* !CONFIG_ANDROID */ tegra_dc_mask_interrupt(dc, FRAME_END_INT); } diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index f69048f62cc2..b7aa066751fc 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -55,9 +55,6 @@ struct tegra_fb_info { bool valid; struct resource *fb_mem; - - int xres; - int yres; }; /* palette array used by the fbcon */ @@ -75,10 +72,18 @@ static int tegra_fb_check_var(struct fb_var_screeninfo *var, info->screen_size) return -EINVAL; + fb_var_to_videomode(&mode, var); + +#if defined(CONFIG_MACH_APALIS_T30) || defined(CONFIG_MACH_COLIBRI_T20) || \ +defined(CONFIG_MACH_COLIBRI_T30) + /* Hack: avoid 24 Hz mode in X resulting in no display at all */ + if (mode.refresh < 50) + return -EINVAL; +#endif /* CONFIG_MACH_APALIS_T30 | CONFIG_MACH_COLIBRI_T20 | + CONFIG_MACH_COLIBRI_T30 */ + /* Apply mode filter for HDMI only -LVDS supports only fix mode */ if (ops && ops->mode_filter) { - - fb_var_to_videomode(&mode, var); if (!ops->mode_filter(dc, &mode)) return -EINVAL; @@ -87,8 +92,35 @@ static int tegra_fb_check_var(struct fb_var_screeninfo *var, } /* Double yres_virtual to allow double buffering through pan_display */ + var->xres_virtual = var->xres; var->yres_virtual = var->yres * 2; + /* we only support RGB ordering for now */ + switch (var->bits_per_pixel) { + case 32: + case 24: + var->bits_per_pixel = 32; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + case 16: + default: + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + } + return 0; } @@ -97,103 +129,61 @@ static int tegra_fb_set_par(struct fb_info *info) struct tegra_fb_info *tegra_fb = info->par; struct fb_var_screeninfo *var = &info->var; struct tegra_dc *dc = tegra_fb->win->dc; + int err; - if (var->bits_per_pixel) { - /* we only support RGB ordering for now */ - switch (var->bits_per_pixel) { - case 32: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 16; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8; - break; - case 16: - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5; - break; - - default: - return -EINVAL; - } - /* if line_length unset, then pad the stride */ - info->fix.line_length = var->xres * var->bits_per_pixel / 8; - info->fix.line_length = round_up(info->fix.line_length, - TEGRA_LINEAR_PITCH_ALIGNMENT); - tegra_fb->win->stride = info->fix.line_length; - tegra_fb->win->stride_uv = 0; - tegra_fb->win->phys_addr_u = 0; - tegra_fb->win->phys_addr_v = 0; - } - - if (var->pixclock) { - bool stereo; - unsigned old_len = 0; - struct fb_videomode m; - struct fb_videomode *old_mode = NULL; - - fb_var_to_videomode(&m, var); + struct tegra_dc_mode mode; - /* Load framebuffer info with new mode details*/ - old_mode = info->mode; - old_len = info->fix.line_length; - - info->mode = (struct fb_videomode *) - fb_find_nearest_mode(&m, &info->modelist); - if (!info->mode) { - dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n"); - info->mode = old_mode; - return -EINVAL; - } + /* This is usually altered to 16/32 by tegra_fb_check_var + * above which is called before this function + */ + switch (var->bits_per_pixel) { + case 32: + tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8; + break; + case 16: + tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5; + break; + default: + return -EINVAL; + break; + } - /* Update fix line_length and window stride as per new mode */ - info->fix.line_length = var->xres * var->bits_per_pixel / 8; - info->fix.line_length = round_up(info->fix.line_length, - TEGRA_LINEAR_PITCH_ALIGNMENT); - tegra_fb->win->stride = info->fix.line_length; + /* if line_length unset, then pad the stride */ + info->fix.line_length = var->xres * var->bits_per_pixel / 8; + info->fix.line_length = round_up(info->fix.line_length, + TEGRA_LINEAR_PITCH_ALIGNMENT); + tegra_fb->win->stride = info->fix.line_length; + tegra_fb->win->stride_uv = 0; + tegra_fb->win->phys_addr_u = 0; + tegra_fb->win->phys_addr_v = 0; + + tegra_fb->win->w.full = dfixed_const(var->xres); + tegra_fb->win->h.full = dfixed_const(var->yres); + tegra_fb->win->out_w = var->xres; + tegra_fb->win->out_h = var->yres; + + dev_info(&tegra_fb->ndev->dev, "switching framebuffer to %dx%d\n", + var->xres, var->yres); + + err = tegra_dc_var_to_dc_mode(dc, var, &mode); + if (err) { + dev_warn(&tegra_fb->ndev->dev, "could not convert var %d\n", err); + return -EINVAL; + } - /* - * only enable stereo if the mode supports it and - * client requests it - */ - stereo = !!(var->vmode & info->mode->vmode & -#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT - FB_VMODE_STEREO_FRAME_PACK); -#else - FB_VMODE_STEREO_LEFT_RIGHT); -#endif + err = tegra_dc_set_mode(dc, &mode); + if (err) { + dev_warn(&tegra_fb->ndev->dev, "could not set dc mode %d\n", err); + return -EINVAL; + } - /* Configure DC with new mode */ - if (tegra_dc_set_fb_mode(dc, info->mode, stereo)) { - /* Error while configuring DC, fallback to old mode */ - dev_warn(&tegra_fb->ndev->dev, "can't configure dc with mode %ux%u\n", - info->mode->xres, info->mode->yres); - info->mode = old_mode; - info->fix.line_length = old_len; - tegra_fb->win->stride = old_len; - return -EINVAL; - } + /* Reflect changes on HW */ + if (dc->enabled) + tegra_dc_disable(dc); + tegra_dc_enable(dc); - /* Reflect mode chnage on DC HW */ - if (dc->enabled) - tegra_dc_disable(dc); - tegra_dc_enable(dc); + return err; - tegra_fb->win->w.full = dfixed_const(info->mode->xres); - tegra_fb->win->h.full = dfixed_const(info->mode->yres); - tegra_fb->win->out_w = info->mode->xres; - tegra_fb->win->out_h = info->mode->yres; - } - return 0; } static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -417,6 +407,9 @@ static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long } int tegra_fb_get_mode(struct tegra_dc *dc) { + /* Avoid error when reading sysfs */ + if (dc->fb->info->mode == NULL) + return 0; return dc->fb->info->mode->refresh; } @@ -532,13 +525,11 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info, /* Prepare a mode db */ for (i = 0; i < specs->modedb_len; i++) { if (info->fbops->fb_check_var) { - struct fb_videomode m; - /* Call mode filter to check mode */ fb_videomode_to_var(&var, &specs->modedb[i]); if (!(info->fbops->fb_check_var(&var, info))) { - fb_var_to_videomode(&m, &var); - fb_add_videomode(&m, + fb_var_to_videomode(&specs->modedb[i], &var); + fb_add_videomode(&specs->modedb[i], &fb_info->info->modelist); /* EDID stds recommend first detailed mode to be applied as default,but if first mode @@ -584,6 +575,106 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info, mutex_unlock(&fb_info->info->lock); } +struct tegra_dc_out_pin dc_out_pins[4]; + + +static int parse_opt(struct tegra_dc_out *out, char *this_opt) +{ + if (!strncmp(this_opt, "hsync:", 6)) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { + out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol = + TEGRA_DC_OUT_PIN_POL_LOW; + } else { + out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol = + TEGRA_DC_OUT_PIN_POL_HIGH; + } + return 0; + } else if (!strncmp(this_opt, "vsync:", 6)) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { + out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol = + TEGRA_DC_OUT_PIN_POL_LOW; + } else { + out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol = + TEGRA_DC_OUT_PIN_POL_HIGH; + } + return 0; + } else if (!strncmp(this_opt, "outputen:", 9)) { + if (simple_strtoul(this_opt+9, NULL, 0) == 0) { + out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol = + TEGRA_DC_OUT_PIN_POL_LOW; + } else { + out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol = + TEGRA_DC_OUT_PIN_POL_HIGH; + } + return 0; + } else if (!strncmp(this_opt, "pixclockpol:", 12)) { + if (simple_strtoul(this_opt+12, NULL, 0) == 0) { + out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol = + TEGRA_DC_OUT_PIN_POL_LOW; + } else { + out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol = + TEGRA_DC_OUT_PIN_POL_HIGH; + } + return 0; + } + + return -1; +} + +static void tegra_dc_copy_pin_modes(struct tegra_dc_out *out) +{ + int i; + struct tegra_dc_out_pin *def = out->out_pins; + int n_out_pins_default = out->n_out_pins; + + /* Allocate memory for dynamic output pin configuration... */ + out->n_out_pins = 4; + out->out_pins = kmalloc(sizeof(struct tegra_dc_out_pin) * out->n_out_pins, + GFP_KERNEL); + + /* ...set fallback values, we use the pin enum as array index... */ + out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].name = TEGRA_DC_OUT_PIN_DATA_ENABLE; + out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol = TEGRA_DC_OUT_PIN_POL_HIGH; + out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].name = TEGRA_DC_OUT_PIN_H_SYNC; + out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol = TEGRA_DC_OUT_PIN_POL_LOW; + out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].name = TEGRA_DC_OUT_PIN_V_SYNC; + out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol = TEGRA_DC_OUT_PIN_POL_LOW; + out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK; + out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol = TEGRA_DC_OUT_PIN_POL_LOW; + + /* ... and copy the static default config from platform data */ + for (i = 0; i < n_out_pins_default; i++) + out->out_pins[def[i].name].pol = def[i].pol; +} + +static int tegra_parse_options(struct tegra_dc_out *out, struct fb_info *info, + char *option) +{ + char *this_opt; + + /* This off option works perfectly for framebuffer + * device, however the tegra binary driver somehow + * has troubles to handle a missing fb0 + * (then, dc1 gets remapped to fb0, which seems + * to be an issue for the binary driver)... + */ + if (!strcmp(option, "off")) + return -ENODEV; + + while ((this_opt = strsep(&option, ",")) != NULL) { + /* Parse driver specific arguments for RGB output */ + if (out->type == TEGRA_DC_OUT_RGB) { + if (parse_opt(out, this_opt) == 0) + continue; + } + + /* No valid driver specific argument, has to be mode */ + if (!tegra_fb_find_mode(&info->var, info, this_opt, 16)) + return -EINVAL; + } + return 0; +} + struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, struct tegra_dc *dc, struct tegra_fb_data *fb_data, @@ -597,6 +688,9 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, unsigned long fb_phys = 0; int ret = 0; unsigned stride; + char *param_option = NULL; + char *option = NULL; + char driver[10]; win = tegra_dc_get_window(dc, fb_data->win); if (!win) { @@ -615,8 +709,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, tegra_fb->win = win; tegra_fb->ndev = ndev; tegra_fb->fb_mem = fb_mem; - tegra_fb->xres = fb_data->xres; - tegra_fb->yres = fb_data->yres; if (fb_mem) { fb_size = resource_size(fb_mem); @@ -653,6 +745,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, info->var.xres_virtual = fb_data->xres; info->var.yres_virtual = fb_data->yres * 2; info->var.bits_per_pixel = fb_data->bits_per_pixel; + info->var.activate = FB_ACTIVATE_VBL; info->var.height = tegra_dc_get_out_height(dc); info->var.width = tegra_dc_get_out_width(dc); @@ -665,11 +758,11 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, info->var.vsync_len = 0; info->var.vmode = FB_VMODE_NONINTERLACED; + /* window settings */ win->x.full = dfixed_const(0); win->y.full = dfixed_const(0); win->w.full = dfixed_const(fb_data->xres); win->h.full = dfixed_const(fb_data->yres); - /* TODO: set to output res dc */ win->out_x = 0; win->out_y = 0; win->out_w = fb_data->xres; @@ -683,6 +776,32 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, win->stride_uv = 0; win->flags = TEGRA_WIN_FLAG_ENABLED; + /* Set/copy default pin modes, if output is RGB... */ + if (dc->out->type == TEGRA_DC_OUT_RGB) + tegra_dc_copy_pin_modes(dc->out); + + /* try to use kernel cmd line specified mode */ + sprintf(driver, "tegrafb%d", ndev->id); + fb_get_options(driver, ¶m_option); + if (param_option != NULL) { + option = param_option; + dev_info(&ndev->dev, "use cmd options for %s: %s\n", + driver, option); + } else { + option = dc->out->default_mode; + dev_info(&ndev->dev, "use default mode for %s: %s\n", + driver, option); + } + + if (option != NULL) { + ret = tegra_parse_options(dc->out, info, option); + if (ret < 0) + goto err_iounmap_fb; + } + + /* Activate current settings (tegra_fb_find_mode has call + * tegra_fb_check_var already) + */ if (fb_mem) tegra_fb_set_par(info); @@ -701,26 +820,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, tegra_dc_sync_windows(&tegra_fb->win, 1); } - if (dc->mode.pclk > 1000) { - struct tegra_dc_mode *mode = &dc->mode; - struct fb_videomode vmode; - - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) - info->var.pixclock = KHZ2PICOS(mode->rated_pclk / 1000); - else - info->var.pixclock = KHZ2PICOS(mode->pclk / 1000); - info->var.left_margin = mode->h_back_porch; - info->var.right_margin = mode->h_front_porch; - info->var.upper_margin = mode->v_back_porch; - info->var.lower_margin = mode->v_front_porch; - info->var.hsync_len = mode->h_sync_width; - info->var.vsync_len = mode->v_sync_width; - - /* Keep info->var consistent with info->modelist. */ - fb_var_to_videomode(&vmode, &info->var); - fb_add_videomode(&vmode, &info->modelist); - } - return tegra_fb; err_iounmap_fb: diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c index 4614689ec37c..2b92a62cc0bc 100644 --- a/drivers/video/tegra/host/bus_client.c +++ b/drivers/video/tegra/host/bus_client.c @@ -611,6 +611,7 @@ fail: nvhost_free_channel(ch); return err; } +EXPORT_SYMBOL(nvhost_client_device_init); int nvhost_client_device_suspend(struct nvhost_device *dev) { @@ -658,6 +659,7 @@ fail: return -ENXIO; } +EXPORT_SYMBOL(nvhost_client_device_get_resources); void nvhost_client_device_put_resources(struct nvhost_device *dev) { @@ -670,3 +672,4 @@ void nvhost_client_device_put_resources(struct nvhost_device *dev) release_mem_region(r->start, resource_size(r)); } +EXPORT_SYMBOL(nvhost_client_device_put_resources); diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c index 5bde55ad2ff5..f22c91ac03f1 100644 --- a/drivers/video/tegra/host/nvhost_acm.c +++ b/drivers/video/tegra/host/nvhost_acm.c @@ -639,8 +639,10 @@ void nvhost_module_busy_ext(struct nvhost_device *dev) { nvhost_module_busy(dev); } +EXPORT_SYMBOL(nvhost_module_busy_ext); void nvhost_module_idle_ext(struct nvhost_device *dev) { nvhost_module_idle(dev); } +EXPORT_SYMBOL(nvhost_module_idle_ext); diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c index 38c28ca116e7..de3e04f65cdd 100644 --- a/drivers/video/tegra/host/nvhost_syncpt.c +++ b/drivers/video/tegra/host/nvhost_syncpt.c @@ -493,12 +493,14 @@ void nvhost_syncpt_cpu_incr_ext(struct nvhost_device *dev, u32 id) struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt); nvhost_syncpt_cpu_incr(sp, id); } +EXPORT_SYMBOL(nvhost_syncpt_cpu_incr_ext); u32 nvhost_syncpt_read_ext(struct nvhost_device *dev, u32 id) { struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt); return nvhost_syncpt_read(sp, id); } +EXPORT_SYMBOL(nvhost_syncpt_read_ext); int nvhost_syncpt_wait_timeout_ext(struct nvhost_device *dev, u32 id, u32 thresh, u32 timeout, u32 *value) @@ -506,3 +508,4 @@ int nvhost_syncpt_wait_timeout_ext(struct nvhost_device *dev, u32 id, u32 thresh struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt); return nvhost_syncpt_wait_timeout(sp, id, thresh, timeout, value); } +EXPORT_SYMBOL(nvhost_syncpt_wait_timeout_ext); diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c index 19b821d41284..e66ca982f2f3 100644 --- a/drivers/video/tegra/nvmap/nvmap.c +++ b/drivers/video/tegra/nvmap/nvmap.c @@ -387,6 +387,7 @@ phys_addr_t nvmap_pin(struct nvmap_client *client, return ret ?: phys; } +EXPORT_SYMBOL(nvmap_pin); phys_addr_t nvmap_handle_address(struct nvmap_client *c, unsigned long id) { @@ -413,6 +414,7 @@ void nvmap_unpin(struct nvmap_client *client, struct nvmap_handle_ref *ref) if (handle_unpin(client, ref->handle, false)) wake_up(&client->share->pin_wait); } +EXPORT_SYMBOL(nvmap_unpin); void nvmap_unpin_handles(struct nvmap_client *client, struct nvmap_handle **h, int nr) @@ -501,6 +503,7 @@ void *nvmap_mmap(struct nvmap_handle_ref *ref) * nvmap_handle_put will be called by unmapping this address */ return p; } +EXPORT_SYMBOL(nvmap_mmap); void nvmap_munmap(struct nvmap_handle_ref *ref, void *addr) { @@ -523,6 +526,7 @@ void nvmap_munmap(struct nvmap_handle_ref *ref, void *addr) } nvmap_handle_put(h); } +EXPORT_SYMBOL(nvmap_munmap); struct nvmap_handle_ref *nvmap_alloc(struct nvmap_client *client, size_t size, size_t align, unsigned int flags, @@ -550,6 +554,7 @@ struct nvmap_handle_ref *nvmap_alloc(struct nvmap_client *client, size_t size, return r; } +EXPORT_SYMBOL(nvmap_alloc); /* allocates memory with specifed iovm_start address. */ struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client, @@ -605,6 +610,7 @@ void nvmap_free(struct nvmap_client *client, struct nvmap_handle_ref *r) nvmap_free_handle_id(client, nvmap_ref_to_id(r)); } +EXPORT_SYMBOL(nvmap_free); int nvmap_mark_global(struct nvmap_client *client, struct nvmap_handle_ref *r) { diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c index 3b0db14f16ca..3ea7bd2ea797 100644 --- a/drivers/video/tegra/nvmap/nvmap_dev.c +++ b/drivers/video/tegra/nvmap/nvmap_dev.c @@ -87,6 +87,7 @@ struct nvmap_device { }; struct nvmap_device *nvmap_dev; +EXPORT_SYMBOL(nvmap_dev); static struct backing_dev_info nvmap_bdi = { .ra_pages = 0, @@ -670,6 +671,7 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev, spin_unlock(&dev->clients_lock); return client; } +EXPORT_SYMBOL(nvmap_create_client); static void destroy_client(struct nvmap_client *client) { @@ -756,6 +758,7 @@ void nvmap_client_put(struct nvmap_client *client) if (!atomic_dec_return(&client->count)) destroy_client(client); } +EXPORT_SYMBOL(nvmap_client_put); static int nvmap_open(struct inode *inode, struct file *filp) { diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c index 4b7760b22190..c1add8383e83 100644 --- a/drivers/video/tegra/nvmap/nvmap_handle.c +++ b/drivers/video/tegra/nvmap/nvmap_handle.c @@ -572,9 +572,10 @@ static int handle_page_alloc(struct nvmap_client *client, #ifdef CONFIG_NVMAP_PAGE_POOLS struct nvmap_page_pool *pool = NULL; struct nvmap_share *share = nvmap_get_share_from_dev(h->dev); + unsigned long paddr; #endif gfp_t gfp = GFP_NVMAP; - unsigned long kaddr, paddr; + unsigned long kaddr; pte_t **pte = NULL; if (h->userflags & NVMAP_HANDLE_ZEROED_PAGES) { diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9a94f7e093dd..8d41441b05ed 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -217,17 +217,20 @@ config TEGRA_WATCHDOG depends on ARCH_TEGRA help Say Y here to include support for the watchdog timer - embedded in NVIDIA Tegra SoCs. + embedded in NVIDIA Tegra SoCs. The default timeout + is set to 60 seconds. To compile this driver as a module, choose M here: the module will be called tegra_wdt. -config TEGRA_WATCHDOG_ENABLE_ON_PROBE - tristate "Turn on Tegra watchdog at system start up" - depends on ARCH_TEGRA && TEGRA_WATCHDOG +config TEGRA_WATCHDOG_ENABLE_HEARTBEAT + bool "Use the first Tegra watchdog as kernel heartbeats" + depends on TEGRA_WATCHDOG + default n help - Say Y here to enable the tegra watchdog at driver - probe time, rather than when the device is opened. + Say Y here to enable the first tegra watchdog at driver + probe time. The kernel will reload the watchdog by + itself in an interrupt handler. config EP93XX_WATCHDOG tristate "EP93xx Watchdog" diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index 1bcd726ebbd6..d32c516b2c55 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c @@ -4,6 +4,7 @@ * watchdog driver for NVIDIA tegra internal watchdog * * Copyright (c) 2012, NVIDIA Corporation. + * Copyright (c) 2013, Toradex AG * * based on drivers/watchdog/softdog.c and drivers/watchdog/omap_wdt.c * @@ -42,13 +43,33 @@ /* minimum and maximum watchdog trigger periods, in seconds */ #define MIN_WDT_PERIOD 5 #define MAX_WDT_PERIOD 1000 + /* Assign Timer 7 to Timer 10 for WDT0 to WDT3, respectively */ #define TMR_SRC_START 7 +/* + * For spinlock lockup detection to work, the heartbeat should be 2*lockup + * for cases where the spinlock disabled irqs. + * Must be between MIN_WDT_PERIOD and MAX_WDT_PERIOD + */ +#define WDT_DEFAULT_TIME 60 + +static int heartbeat = WDT_DEFAULT_TIME; +static bool nowayout = WATCHDOG_NOWAYOUT; + +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat period in seconds (default=" + __MODULE_STRING(WDT_DEFAULT_TIME)); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +#endif enum tegra_wdt_status { WDT_DISABLED = 1 << 0, WDT_ENABLED = 1 << 1, - WDT_ENABLED_AT_PROBE = 1 << 2, + WDT_KERNEL_HEARTBEAT = 1 << 2, }; struct tegra_wdt { @@ -61,18 +82,15 @@ struct tegra_wdt { void __iomem *wdt_source; void __iomem *wdt_timer; void __iomem *int_base; - int irq; int tmrsrc; int timeout; int status; + int way_out_ok; + struct tasklet_struct tasklet; + int irq; + int irq_counter; }; -/* - * For spinlock lockup detection to work, the heartbeat should be 2*lockup - * for cases where the spinlock disabled irqs. - */ -static int heartbeat = 120; /* must be greater than MIN_WDT_PERIOD and lower than MAX_WDT_PERIOD */ - #if defined(CONFIG_ARCH_TEGRA_2x_SOC) #define TIMER_PTV 0x0 @@ -107,6 +125,16 @@ static void tegra_wdt_disable(struct tegra_wdt *wdt) static inline void tegra_wdt_ping(struct tegra_wdt *wdt) { + /* Reset timer */ + tegra_wdt_enable(wdt); + + /* Reenable IRQ in case an interrupt already happend */ + if (wdt->irq_counter) { + writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR); + wdt->irq_counter = 0; + enable_irq(wdt->irq); + } + return; } @@ -114,9 +142,30 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id) { struct tegra_wdt *wdt = dev_id; - writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR); + wdt->irq_counter++; + + if (wdt->status & WDT_KERNEL_HEARTBEAT) { + tegra_wdt_ping(wdt); + } else { + /* If not in heartbeat mode, disable IRQs to avoid IRQ storm + * We don't acknowledge the interrupt here since the user + * did not reload the timer in time. Upon next interrupt + * the system will reset... + */ + tasklet_schedule(&wdt->tasklet); + disable_irq_nosync(irq); + } + return IRQ_HANDLED; } + +static void tegra_wdt_do_tasklet(unsigned long data) +{ + struct tegra_wdt *wdt = (struct tegra_wdt *)data; + dev_info(wdt->miscdev.parent, "Watchdog interrupt received, system " + "will reset soon if no ping arrives\n"); +} + #elif defined(CONFIG_ARCH_TEGRA_3x_SOC) #define TIMER_PTV 0 @@ -132,6 +181,7 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id) #define WDT_CFG_PMC2CAR_RST_EN (1 << 15) #define WDT_STATUS (4) #define WDT_INTR_STAT (1 << 1) + #define WDT_STATUS_EXPIR_COUNTER (3 << 12) #define WDT_CMD (8) #define WDT_CMD_START_COUNTER (1 << 0) #define WDT_CMD_DISABLE_COUNTER (1 << 1) @@ -169,19 +219,21 @@ static void tegra_wdt_enable(struct tegra_wdt *wdt) val |= (TIMER_EN | TIMER_PERIODIC); writel(val, wdt->wdt_timer + TIMER_PTV); - /* Interrupt handler is not required for user space - * WDT accesses, since the caller is responsible to ping the - * WDT to reset the counter before expiration, through ioctls. + writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD); + + /* Interrupt handler is not required for user space since + * a warning in a fourth of time don't make sense. Then + * the interrupt line is also shared, so it can't be disabled + * if one watchdog is about to expire... (interrupt storm) * SYS_RST_EN doesnt work as there is no external reset * from Tegra. */ - val = wdt->tmrsrc | WDT_CFG_PERIOD | /*WDT_CFG_INT_EN |*/ + val = wdt->tmrsrc | WDT_CFG_PERIOD | /* WDT_CFG_INT_EN | */ /*WDT_CFG_SYS_RST_EN |*/ WDT_CFG_PMC2CAR_RST_EN; #ifdef CONFIG_TEGRA_FIQ_DEBUGGER val |= WDT_CFG_FIQ_INT_EN; #endif writel(val, wdt->wdt_source + WDT_CFG); - writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD); } static void tegra_wdt_disable(struct tegra_wdt *wdt) @@ -192,17 +244,30 @@ static void tegra_wdt_disable(struct tegra_wdt *wdt) writel(0, wdt->wdt_timer + TIMER_PTV); } +static void tegra_wdt_interrupt_instance(struct tegra_wdt *wdt) +{ + WARN_ON_ONCE(!(wdt->status & WDT_KERNEL_HEARTBEAT)); + + if (wdt->status & WDT_KERNEL_HEARTBEAT) { + tegra_wdt_ping(wdt); + } +} + static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id) { + struct tegra_wdt *wdt = NULL; unsigned i, status; for (i = 0; i < MAX_NR_CPU_WDT; i++) { - if (tegra_wdt[i] == NULL) + wdt = tegra_wdt[i]; + if (wdt == NULL) continue; - status = readl(tegra_wdt[i]->wdt_source + WDT_STATUS); - if ((tegra_wdt[i]->status & WDT_ENABLED) && - (status & WDT_INTR_STAT)) - tegra_wdt_ping(tegra_wdt[i]); + status = readl(wdt->wdt_source + WDT_STATUS); + if ((wdt->status & WDT_ENABLED) && + (status & WDT_INTR_STAT)) + { + tegra_wdt_interrupt_instance(wdt); + } } return IRQ_HANDLED; @@ -228,6 +293,9 @@ static int tegra_wdt_open(struct inode *inode, struct file *file) if (test_and_set_bit(1, &wdt->users)) return -EBUSY; + /* Reset no way out, we need a new magic again */ + wdt->way_out_ok = 0; + wdt->status |= WDT_ENABLED; wdt->timeout = heartbeat; tegra_wdt_enable(wdt); @@ -239,13 +307,19 @@ static int tegra_wdt_release(struct inode *inode, struct file *file) { struct tegra_wdt *wdt = file->private_data; - if (wdt->status == WDT_ENABLED) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - tegra_wdt_disable(wdt); - wdt->status = WDT_DISABLED; -#endif + if (wdt->status & WDT_ENABLED && !nowayout) { + if (wdt->way_out_ok) { + tegra_wdt_disable(wdt); + wdt->status = WDT_DISABLED; + } else { + dev_info(wdt->miscdev.parent, "No Magic Close " + "received, watchdog not disabled!\n"); + } + } else if (nowayout) { + dev_info(wdt->miscdev.parent, "No way out is " + "enabled, watchdog not disabled!\n"); } - wdt->users = 0; + clear_bit(1, &wdt->users); return 0; } @@ -288,11 +362,10 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd, return put_user(wdt->timeout, (int __user *)arg); case WDIOC_SETOPTIONS: -#ifndef CONFIG_WATCHDOG_NOWAYOUT if (get_user(option, (int __user *)arg)) return -EFAULT; spin_lock(&lock); - if (option & WDIOS_DISABLECARD) { + if (option & WDIOS_DISABLECARD && !nowayout) { wdt->status &= ~WDT_ENABLED; wdt->status |= WDT_DISABLED; tegra_wdt_disable(wdt); @@ -306,9 +379,6 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd, } spin_unlock(&lock); return 0; -#else - return -EINVAL; -#endif } return -ENOTTY; } @@ -316,6 +386,19 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd, static ssize_t tegra_wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { + struct tegra_wdt *wdt = file->private_data; + + /* check if way-out char was written as last data */ + char c; + if(len) { + tegra_wdt_ping(wdt); + + if(get_user(c, data + len - 1)) + return -EFAULT; + else + wdt->way_out_ok = (('V' == c) ? 1 : 0); + } + return len; } @@ -333,8 +416,14 @@ static int tegra_wdt_probe(struct platform_device *pdev) struct resource *res_src, *res_wdt, *res_irq; struct resource *res_int_base = NULL; struct tegra_wdt *wdt; - u32 src; int ret = 0; +#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_HEARTBEAT +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + int is_heartbeat_wdt = 1; +#else + int is_heartbeat_wdt = !(pdev->id); +#endif +#endif if (pdev->id < -1 && pdev->id > 3) { dev_err(&pdev->dev, "only IDs 3:0 supported\n"); @@ -369,7 +458,6 @@ static int tegra_wdt_probe(struct platform_device *pdev) return -ENOMEM; } - wdt->irq = -1; wdt->miscdev.parent = &pdev->dev; if (pdev->id == -1) { wdt->miscdev.minor = WATCHDOG_MINOR; @@ -410,12 +498,17 @@ static int tegra_wdt_probe(struct platform_device *pdev) goto fail; } - src = readl(wdt->wdt_source); - if (src & BIT(12)) +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + /* Watchdog of Tegra 3 are not at the reset controller regs */ + if (readl(wdt->wdt_source) & BIT(12)) dev_info(&pdev->dev, "last reset due to watchdog timeout\n"); +#endif tegra_wdt_disable(wdt); writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR); +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD); +#endif if (res_irq != NULL) { #ifdef CONFIG_TEGRA_FIQ_DEBUGGER @@ -436,6 +529,7 @@ static int tegra_wdt_probe(struct platform_device *pdev) goto fail; tegra_wdt_int_priority(wdt); #endif + wdt->irq = -1; ret = request_irq(res_irq->start, tegra_wdt_interrupt, IRQF_DISABLED, dev_name(&pdev->dev), wdt); if (ret) { @@ -464,24 +558,26 @@ static int tegra_wdt_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, wdt); +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + tasklet_init(&wdt->tasklet, tegra_wdt_do_tasklet, (unsigned long)wdt); +#endif -#ifndef CONFIG_ARCH_TEGRA_2x_SOC -#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_ON_PROBE - /* Init and enable watchdog on WDT0 with timer 8 during probe */ - if (!(pdev->id)) { - u32 val = 0; - wdt->status = WDT_ENABLED | WDT_ENABLED_AT_PROBE; +#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_HEARTBEAT + /* Enable first watchdog during probe */ + if (is_heartbeat_wdt) { + wdt->status = WDT_ENABLED | WDT_KERNEL_HEARTBEAT; wdt->timeout = heartbeat; + set_bit(1, &wdt->users); tegra_wdt_enable(wdt); - val = readl(wdt->wdt_source + WDT_CFG); - val |= WDT_CFG_INT_EN; - writel(val, wdt->wdt_source + WDT_CFG); - pr_info("WDT heartbeat enabled on probe\n"); + pr_info("WDT kernel heartbeat enabled on probe\n"); } #endif + +#ifndef CONFIG_ARCH_TEGRA_2x_SOC tegra_wdt[pdev->id] = wdt; #endif - pr_info("%s done\n", __func__); + + dev_info(&pdev->dev, "%s done\n", __func__); return 0; fail: if (wdt->irq != -1) @@ -543,16 +639,6 @@ static int tegra_wdt_resume(struct platform_device *pdev) if (wdt->status & WDT_ENABLED) tegra_wdt_enable(wdt); -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* Enable interrupt for WDT3 heartbeat watchdog */ - if (wdt->status & WDT_ENABLED_AT_PROBE) { - u32 val = 0; - val = readl(wdt->wdt_source + WDT_CFG); - val |= WDT_CFG_INT_EN; - writel(val, wdt->wdt_source + WDT_CFG); - pr_info("WDT heartbeat enabled on probe\n"); - } -#endif return 0; } #endif @@ -586,10 +672,6 @@ module_exit(tegra_wdt_exit); MODULE_AUTHOR("NVIDIA Corporation"); MODULE_DESCRIPTION("Tegra Watchdog Driver"); -module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, - "Watchdog heartbeat period in seconds"); - MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS("platform:tegra_wdt"); diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index d494001b1226..fcdcb5d5c995 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -170,6 +170,16 @@ extern int __gpio_cansleep(unsigned gpio); extern int __gpio_to_irq(unsigned gpio); +#define GPIOF_DIR_OUT (0 << 0) +#define GPIOF_DIR_IN (1 << 0) + +#define GPIOF_INIT_LOW (0 << 1) +#define GPIOF_INIT_HIGH (1 << 1) + +#define GPIOF_IN (GPIOF_DIR_IN) +#define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW) +#define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH) + /** * struct gpio - a structure describing a GPIO with configuration * @gpio: the GPIO number diff --git a/include/linux/colibri_usb.h b/include/linux/colibri_usb.h new file mode 100644 index 000000000000..6b3949979c38 --- /dev/null +++ b/include/linux/colibri_usb.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _COLIBRI_USB_H_ +#define _COLIBRI_USB_H_ + +struct colibri_otg_platform_data { + int cable_detect_gpio; + struct platform_device* (*host_register)(void); + void (*host_unregister)(struct platform_device*); +}; + +#endif /* _COLIBRI_USB_H_ */ diff --git a/include/linux/input/fusion_F0710A.h b/include/linux/input/fusion_F0710A.h new file mode 100644 index 000000000000..7d152cbdd06e --- /dev/null +++ b/include/linux/input/fusion_F0710A.h @@ -0,0 +1,20 @@ +/* linux/input/fusion_F0710A.h + * + * Platform data for Fusion F0710A driver + * + * Copyright (c) 2013 Toradex AG (stefan.agner@toradex.ch) + * + * For licencing details see kernel-base/COPYING + */ + +#ifndef __LINUX_I2C_FUSION_F0710A_H +#define __LINUX_I2C_FUSION_F0710A_H + +/* Board specific touch screen initial values */ +struct fusion_f0710a_init_data { + int (*pinmux_fusion_pins)(void); + int gpio_int; + int gpio_reset; +}; + +#endif /* __LINUX_I2C_FUSION_F0710A_H */ diff --git a/include/linux/linux_logo.h b/include/linux/linux_logo.h index ca5bd91d12e1..2be299513819 100644 --- a/include/linux/linux_logo.h +++ b/include/linux/linux_logo.h @@ -47,6 +47,7 @@ extern const struct linux_logo logo_superh_vga16; extern const struct linux_logo logo_superh_clut224; extern const struct linux_logo logo_m32r_clut224; extern const struct linux_logo logo_spe_clut224; +extern const struct linux_logo logo_custom_clut224; extern const struct linux_logo *fb_find_logo(int depth); #ifdef CONFIG_FB_LOGO_EXTRA diff --git a/include/linux/lm95245.h b/include/linux/lm95245.h new file mode 100644 index 000000000000..ecc7ec57696a --- /dev/null +++ b/include/linux/lm95245.h @@ -0,0 +1,37 @@ +/* + * include/linux/lm95245.h + * + * LM95245, temperature monitoring device from National Semiconductors + * + * Copyright (c) 2013, Toradex, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _LINUX_LM95245_H +#define _LINUX_LM95245_H + +struct lm95245_platform_data { + bool enable_os_pin; + void (*probe_callback)(struct device *dev); +}; + +void lm95245_get_local_temp(struct device *dev, int *temp); +void lm95245_get_remote_temp(struct device *dev, int *temp); +void lm95245_set_remote_os_limit(struct device *dev, int temp); +void lm95245_set_remote_critical_limit(struct device *dev, int temp); +void lm95245_set_local_shared_os__critical_limit(struct device *dev, int val); + +#endif /* _LINUX_LM95245_H */ diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index be1af7c42e57..b584ea64a16a 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h @@ -10,6 +10,17 @@ #include <linux/device.h> +#define SAMPLE_TIME(x) ((x & 0xf) << 4) +#define MOD_12B(x) ((x & 0x1) << 3) +#define REF_SEL(x) ((x & 0x1) << 1) +#define ADC_FREQ(x) (x & 0x3) +#define AVE_CTRL(x) ((x & 0x3) << 6) +#define DET_DELAY(x) ((x & 0x7) << 3) +#define SETTLING(x) (x & 0x7) +#define FRACTION_Z(x) (x & 0x7) +#define I_DRIVE(x) (x & 0x1) +#define OP_MODE(x) ((x & 0x7) << 1) + enum stmpe_block { STMPE_BLOCK_GPIO = 1 << 0, STMPE_BLOCK_KEYPAD = 1 << 1, @@ -174,6 +185,26 @@ struct stmpe_ts_platform_data { }; /** + * struct stmpe_adc_platform_data - stmpe811 adc controller platform + * data + * @sample_time: ADC converstion time in number of clock. + * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks, + * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks), + * recommended is 4. + * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC) + * @ref_sel: ADC reference source + * (0 -> internal reference, 1 -> external reference) + * @adc_freq: ADC Clock speed + * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz) + */ +struct stmpe_adc_platform_data { + u8 sample_time; + u8 mod_12b; + u8 ref_sel; + u8 adc_freq; +}; + +/** * struct stmpe_platform_data - STMPE platform data * @id: device id to distinguish between multiple STMPEs on the same board * @blocks: bitmask of blocks to enable (use STMPE_BLOCK_*) @@ -199,6 +230,7 @@ struct stmpe_platform_data { struct stmpe_gpio_platform_data *gpio; struct stmpe_keypad_platform_data *keypad; struct stmpe_ts_platform_data *ts; + struct stmpe_adc_platform_data *adc; }; #define STMPE_NR_INTERNAL_IRQS 9 diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h index 702cee59cc7b..b5e990e9f6ee 100644 --- a/include/linux/mfd/tps6586x.h +++ b/include/linux/mfd/tps6586x.h @@ -56,7 +56,6 @@ enum pwm_pfm_mode { PWM_ONLY, AUTO_PWM_PFM, PWM_DEFAULT_VALUE, - }; enum slew_rate_settings { @@ -71,6 +70,14 @@ enum slew_rate_settings { SLEW_RATE_DEFAULT_VALUE, }; +enum tps6586x_type { + TPS658621A = 0x15, + TPS658621D = 0x2c, + TPS658623 = 0x1b, + TPS658643 = 0x03, + TPS6586X_ANY = -1, +}; + struct tps6586x_settings { /* SM0, SM1 and SM2 have PWM-only and auto PWM/PFM mode */ enum pwm_pfm_mode sm_pwm_mode; @@ -128,5 +135,6 @@ extern int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask); extern int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask); extern int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask); +extern enum tps6586x_type tps6586x_gettype(struct device *dev); #endif /*__LINUX_MFD_TPS6586X_H */ diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 5ee48390decc..db86304e1c28 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -93,6 +93,8 @@ struct sdhci_host { #define SDHCI_QUIRK_NON_STANDARD_TUNING (1ULL<<33) /* Controller doesn't calculate max_discard_to */ #define SDHCI_QUIRK_NO_CALC_MAX_DISCARD_TO (1ULL<<34) +/* The system physically doesn't support 1.8v, even if the host does */ +#define SDHCI_QUIRK2_NO_1_8_V (1ULL<<35) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h index 59f928aaa07f..9ad666f987ea 100644 --- a/include/linux/platform_data/tegra_usb.h +++ b/include/linux/platform_data/tegra_usb.h @@ -98,6 +98,7 @@ struct tegra_usb_dev_mode_data { */ struct tegra_usb_host_mode_data { int vbus_gpio; + int vbus_gpio_inverted; const char *vbus_reg; bool hot_plug; bool remote_wakeup_supported; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index cc09c562e479..b4793408969d 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -495,14 +495,12 @@ static struct global_cwq *get_gcwq(unsigned int cpu) static atomic_t *get_pool_nr_running(struct worker_pool *pool) { int cpu = pool->gcwq->cpu; - atomic_t (*nr_running)[NR_WORKER_POOLS]; + int idx = worker_pool_pri(pool); if (cpu != WORK_CPU_UNBOUND) - nr_running = &per_cpu(pool_nr_running, cpu); + return &per_cpu(pool_nr_running, cpu)[idx]; else - nr_running = &unbound_pool_nr_running; - - return nr_running[worker_pool_pri(pool)]; + return &unbound_pool_nr_running[idx]; } static struct cpu_workqueue_struct *get_cwq(unsigned int cpu, diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 862dd35260d0..e46cc984f9de 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -480,7 +480,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) else buf2[0] = '\0'; - printk(KERN_INFO "HDMI: supports coding type %s:" + printk(KERN_DEBUG "HDMI: supports coding type %s:" " channels = %d, rates =%s%s\n", cea_audio_coding_type_names[a->format], a->channels, @@ -504,14 +504,14 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) { int i; - printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n", + printk(KERN_DEBUG "HDMI: detected monitor %s at connection type %s\n", e->monitor_name, eld_connection_type_names[e->conn_type]); if (e->spk_alloc) { char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - printk(KERN_INFO "HDMI: available speakers:%s\n", buf); + printk(KERN_DEBUG "HDMI: available speakers:%s\n", buf); } for (i = 0; i < e->sad_count; i++) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5942395099ad..ac509cd68f6f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -702,7 +702,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) int pin_idx; struct hdmi_eld *eld; - printk(KERN_INFO + printk(KERN_DEBUG "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", codec->addr, pin_nid, pd, eldv); @@ -952,7 +952,7 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, if (eld->monitor_present) eld_valid = !!(present & AC_PINSENSE_ELDV); - printk(KERN_INFO + printk(KERN_DEBUG "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", codec->addr, pin_nid, eld->monitor_present, eld_valid); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cb4d30305059..80a520b1ff4b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1188,7 +1188,10 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec) } ass = codec->subsystem_id & 0xffff; +#ifndef CONFIG_MACH_APALIS_T30 +/* Hack: avoid crash due to codec->bus->pci being NULL */ if (ass != codec->bus->pci->subsystem_device && (ass & 1)) +#endif goto do_sku; nid = 0x1d; @@ -1268,7 +1271,10 @@ static int alc_subsystem_id(struct hda_codec *codec, } ass = codec->subsystem_id & 0xffff; +#ifndef CONFIG_MACH_APALIS_T30 +/* Hack: avoid crash due to codec->bus->pci being NULL */ if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) +#endif goto do_sku; /* invalid SSID, check the special NID pin defcfg instead */ @@ -1503,7 +1509,12 @@ static void alc_pick_fixup(struct hda_codec *codec, } } if (id < 0) { +#ifdef CONFIG_MACH_APALIS_T30 +/* Hack: avoid crash due to codec->bus->pci being NULL */ + quirk = NULL; +#else quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); +#endif if (quirk) { id = quirk->value; #ifdef CONFIG_SND_DEBUG_VERBOSE diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 7e4066e131e6..86d46ef9947c 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -20,6 +20,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/consumer.h> +#include <linux/of_device.h> #include <sound/core.h> #include <sound/tlv.h> #include <sound/pcm.h> @@ -130,27 +131,24 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: /* change mic bias resistor to 4Kohm */ snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, - SGTL5000_BIAS_R_4k, SGTL5000_BIAS_R_4k); + SGTL5000_BIAS_R_MASK, + SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT); break; case SND_SOC_DAPM_PRE_PMD: - /* - * SGTL5000_BIAS_R_8k as mask to clean the two bits - * of mic bias and output impedance - */ snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, - SGTL5000_BIAS_R_8k, 0); + SGTL5000_BIAS_R_MASK, 0); break; } return 0; } /* - * using codec assist to small pop, hp_powerup or lineout_powerup - * should stay setting until vag_powerup is fully ramped down, - * vag fully ramped down require 400ms. + * As manual described, ADC/DAC only works when VAG powerup, + * So enabled VAG before ADC/DAC up. + * In power down case, we need wait 400ms when vag fully ramped down. */ -static int small_pop_event(struct snd_soc_dapm_widget *w, +static int power_vag_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { switch (event) { @@ -159,7 +157,7 @@ static int small_pop_event(struct snd_soc_dapm_widget *w, SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); break; - case SND_SOC_DAPM_PRE_PMD: + case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER, SGTL5000_VAG_POWERUP, 0); msleep(400); @@ -204,12 +202,8 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { mic_bias_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0, - small_pop_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA_E("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0, - small_pop_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux), SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &dac_mux), @@ -224,8 +218,11 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { 0, SGTL5000_CHIP_DIG_POWER, 1, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0), + SND_SOC_DAPM_SUPPLY("VAG_POWER", SGTL5000_CHIP_ANA_POWER, 7, 0, + power_vag_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0), SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0), }; @@ -234,13 +231,16 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Capture Mux", "LINE_IN", "LINE_IN"}, /* line_in --> adc_mux */ {"Capture Mux", "MIC_IN", "MIC_IN"}, /* mic_in --> adc_mux */ + {"ADC", NULL, "VAG_POWER"}, {"ADC", NULL, "Capture Mux"}, /* adc_mux --> adc */ {"AIFOUT", NULL, "ADC"}, /* adc --> i2s_out */ + {"DAC", NULL, "VAG_POWER"}, {"DAC", NULL, "AIFIN"}, /* i2s-->dac,skip audio mux */ {"Headphone Mux", "DAC", "DAC"}, /* dac --> hp_mux */ {"LO", NULL, "DAC"}, /* dac --> line_out */ + {"LINE_IN", NULL, "VAG_POWER"}, {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */ {"HP", NULL, "Headphone Mux"}, /* hp_mux --> hp */ @@ -367,7 +367,7 @@ static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0); /* tlv for mic gain, 0db 20db 30db 40db */ static const unsigned int mic_gain_tlv[] = { - TLV_DB_RANGE_HEAD(4), + TLV_DB_RANGE_HEAD(2), 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0), }; @@ -402,7 +402,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { 5, 1, 0), SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL, - 0, 4, 0, mic_gain_tlv), + 0, 3, 0, mic_gain_tlv), }; /* mute the codec used by alsa core */ @@ -725,7 +725,9 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL, i2s_ctl, i2s_ctl); + snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL, + SGTL5000_I2S_DLEN_MASK | SGTL5000_I2S_SCLKFREQ_MASK, + i2s_ctl); return 0; } @@ -756,7 +758,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev) /* set voltage to register */ snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, - (0x1 << 4) - 1, reg); + SGTL5000_LINREG_VDDD_MASK, reg); snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, SGTL5000_LINEREG_D_POWERUP, @@ -782,7 +784,7 @@ static int ldo_regulator_disable(struct regulator_dev *dev) /* clear voltage info */ snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, - (0x1 << 4) - 1, 0); + SGTL5000_LINREG_VDDD_MASK, 0); ldo->enabled = 0; @@ -808,6 +810,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec, int voltage) { struct ldo_regulator *ldo; + struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); ldo = kzalloc(sizeof(struct ldo_regulator), GFP_KERNEL); @@ -842,6 +845,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec, return ret; } + sgtl5000->ldo = ldo; return 0; } @@ -986,12 +990,12 @@ static int sgtl5000_restore_regs(struct snd_soc_codec *codec) /* restore regular registers */ for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) { - /* this regs depends on the others */ + /* These regs should restore in particular order */ if (reg == SGTL5000_CHIP_ANA_POWER || reg == SGTL5000_CHIP_CLK_CTRL || reg == SGTL5000_CHIP_LINREG_CTRL || reg == SGTL5000_CHIP_LINE_OUT_CTRL || - reg == SGTL5000_CHIP_CLK_CTRL) + reg == SGTL5000_CHIP_REF_CTRL) continue; snd_soc_write(codec, reg, cache[reg]); @@ -1002,8 +1006,17 @@ static int sgtl5000_restore_regs(struct snd_soc_codec *codec) snd_soc_write(codec, reg, cache[reg]); /* - * restore power and other regs according - * to set_power() and set_clock() + * restore these regs according to the power setting sequence in + * sgtl5000_set_power_regs() and clock setting sequence in + * sgtl5000_set_clock(). + * + * The order of restore is: + * 1. SGTL5000_CHIP_CLK_CTRL MCLK_FREQ bits (1:0) should be restore after + * SGTL5000_CHIP_ANA_POWER PLL bits set + * 2. SGTL5000_CHIP_LINREG_CTRL should be set before + * SGTL5000_CHIP_ANA_POWER LINREG_D restored + * 3. SGTL5000_CHIP_REF_CTRL controls Analog Ground Voltage, + * prefer to resotre it after SGTL5000_CHIP_ANA_POWER restored */ snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL, cache[SGTL5000_CHIP_LINREG_CTRL]); @@ -1115,7 +1128,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) /* set voltage to register */ snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, - (0x1 << 4) - 1, 0x8); + SGTL5000_LINREG_VDDD_MASK, 0x8); /* * if vddd linear reg has been enabled, @@ -1146,8 +1159,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP; snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL, - vag << SGTL5000_ANA_GND_SHIFT, - vag << SGTL5000_ANA_GND_SHIFT); + SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT); /* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */ vag = vddio / 2; @@ -1161,9 +1173,8 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) SGTL5000_LINE_OUT_GND_STP; snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL, - vag << SGTL5000_LINE_OUT_GND_SHIFT | - SGTL5000_LINE_OUT_CURRENT_360u << - SGTL5000_LINE_OUT_CURRENT_SHIFT, + SGTL5000_LINE_OUT_CURRENT_MASK | + SGTL5000_LINE_OUT_GND_MASK, vag << SGTL5000_LINE_OUT_GND_SHIFT | SGTL5000_LINE_OUT_CURRENT_360u << SGTL5000_LINE_OUT_CURRENT_SHIFT); @@ -1331,7 +1342,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN); - snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 0); + snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2); /* * disable DAP @@ -1436,10 +1447,17 @@ static const struct i2c_device_id sgtl5000_id[] = { MODULE_DEVICE_TABLE(i2c, sgtl5000_id); +static const struct of_device_id sgtl5000_dt_ids[] = { + { .compatible = "fsl,sgtl5000", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids); + static struct i2c_driver sgtl5000_i2c_driver = { .driver = { .name = "sgtl5000", .owner = THIS_MODULE, + .of_match_table = sgtl5000_dt_ids, }, .probe = sgtl5000_i2c_probe, .remove = __devexit_p(sgtl5000_i2c_remove), diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index eec3ab368f39..8a9f43534b79 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h @@ -280,7 +280,7 @@ /* * SGTL5000_CHIP_MIC_CTRL */ -#define SGTL5000_BIAS_R_MASK 0x0200 +#define SGTL5000_BIAS_R_MASK 0x0300 #define SGTL5000_BIAS_R_SHIFT 8 #define SGTL5000_BIAS_R_WIDTH 2 #define SGTL5000_BIAS_R_off 0x0 diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index de8309be3816..a47a746a2b7e 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -4,6 +4,17 @@ config SND_SOC_TEGRA help Say Y or M here if you want support for SoC audio on Tegra. +config SND_SOC_TEGRA20_AC97 + tristate "Tegra 20 AC97 driver" + select AC97_BUS + select SND_AC97_CODEC + select SND_SOC_AC97_BUS + select SND_SOC_TEGRA20_DAS + help + Say Y or M if you want to add support for codecs attached to the + Tegra AC97 interface. You will also need to select the individual + machine drivers to support below. + config SND_SOC_TEGRA20_DAS tristate "Tegra 20 Digital Audio Switch driver" depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC @@ -76,6 +87,29 @@ config SND_SOC_TEGRA_WM8903 boards using the WM8093 codec. Currently, the supported boards are Harmony, Ventana, Seaboard, Kaen, and Aebl. +config SND_SOC_TEGRA_COLIBRI_T20 + tristate "SoC Audio support for Colibri T20 module" + depends on SND_SOC_TEGRA && MACH_COLIBRI_T20 + select SND_SOC_SPDIF + select SND_SOC_TEGRA20_AC97 + select SND_SOC_TEGRA20_SPDIF + select SND_SOC_WM9712 + help + Say Y or M here if you want to add support for SoC audio on the + Toradex Colibri T20 module. + +config SND_SOC_TEGRA_COLIBRI_T30 + tristate "SoC Audio support for Apalis/Colibri T30 modules" + depends on I2C && (MACH_APALIS_T30 || MACH_COLIBRI_T30) && SND_SOC_TEGRA + select SND_SOC_SGTL5000 + select SND_SOC_SPDIF + select SND_SOC_TEGRA30_DAM + select SND_SOC_TEGRA30_I2S + select SND_SOC_TEGRA30_SPDIF + help + Say Y or M here if you want to add support for SoC audio on the + Toradex Apalis/Colibri T30 modules. + config SND_SOC_TEGRA_TRIMSLICE tristate "SoC Audio support for TrimSlice board" depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 83f30054a085..594c963cb8ea 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -8,6 +8,7 @@ snd-soc-tegra-tdm-pcm-objs := tegra_tdm_pcm.o snd-soc-tegra20-spdif-objs := tegra20_spdif.o snd-soc-tegra-utils-objs += tegra_asoc_utils.o snd-soc-tegra20-das-objs := tegra20_das.o +snd-soc-tegra20-ac97-objs := tegra20_ac97.o snd-soc-tegra20-i2s-objs := tegra20_i2s.o snd-soc-tegra30-ahub-objs := tegra30_ahub.o snd-soc-tegra30-i2s-objs := tegra30_i2s.o @@ -18,6 +19,7 @@ obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-tdm-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o +obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o obj-$(CONFIG_SND_SOC_TEGRA30_DAM) += snd-soc-tegra30-dam.o @@ -27,6 +29,8 @@ obj-$(CONFIG_SND_SOC_TEGRA30_SPDIF) += snd-soc-tegra30-spdif.o # Tegra machine Support snd-soc-tegra-wm8903-objs := tegra_wm8903.o +snd-soc-tegra-colibri_t20-objs := colibri_t20.o +snd-soc-tegra-colibri_t30-objs := colibri_t30.o snd-soc-tegra-trimslice-objs := trimslice.o snd-soc-tegra-wm8753-objs := tegra_wm8753.o snd-soc-tegra-max98088-objs := tegra_max98088.o @@ -36,6 +40,8 @@ snd-soc-tegra-max98095-objs := tegra_max98095.o snd-soc-tegra-vcm-objs := tegra_vcm.o obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o +obj-$(CONFIG_SND_SOC_TEGRA_COLIBRI_T20) += snd-soc-tegra-colibri_t20.o +obj-$(CONFIG_SND_SOC_TEGRA_COLIBRI_T30) += snd-soc-tegra-colibri_t30.o obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o obj-$(CONFIG_SND_SOC_TEGRA_MAX98088) += snd-soc-tegra-max98088.o diff --git a/sound/soc/tegra/colibri_t20.c b/sound/soc/tegra/colibri_t20.c new file mode 100644 index 000000000000..744328b7b9ec --- /dev/null +++ b/sound/soc/tegra/colibri_t20.c @@ -0,0 +1,393 @@ +/* + * SoC audio driver for Toradex Colibri T20 + * + * Copyright (C) 2012 Toradex Inc. + * + * 2010-11-19: Marcel Ziswiler <marcel.ziswiler@noser.com> + * initial version (note: WM9715L is fully WM9712 compatible) + * + * Copied from tosa.c: + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * Authors: Liam Girdwood <lrg@slimlogic.co.uk> + * Richard Purdie <richard@openedhand.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <asm/mach-types.h> + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/slab.h> + +#include <mach/audio.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> /* order crucial */ +#include <sound/soc-dapm.h> + +#include "../codecs/wm9712.h" +#include "tegra_asoc_utils.h" +#include "tegra_pcm.h" +#include "tegra20_ac97.h" + +#define DRV_NAME "colibri_t20-snd-wm9715l" + +struct colibri_t20_wm9715l { + struct tegra_asoc_utils_data util_data; +}; + +static int colibri_t20_wm9715l_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = codec->card; + struct colibri_t20_wm9715l *machine = snd_soc_card_get_drvdata(card); + int srate, mclk; + int err; + + srate = params_rate(params); + + /* AC97 clock is really fixed */ + mclk = 24576000; + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + if (!(machine->util_data.set_mclk % mclk)) + mclk = machine->util_data.set_mclk; + else { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + } + + tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); + +//DAS AC97 DAC to DAP switching already done at probe + + return 0; +} + +static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct colibri_t20_wm9715l *machine = snd_soc_card_get_drvdata(card); + int srate, mclk, min_mclk; + int err; + + srate = params_rate(params); + switch (srate) { + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + case 8000: + case 16000: + case 32000: + case 48000: + case 64000: + case 96000: + mclk = 12288000; + break; + default: + return -EINVAL; + } + min_mclk = 128 * srate; + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + if (!(machine->util_data.set_mclk % min_mclk)) + mclk = machine->util_data.set_mclk; + else { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + } + + tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); + + return 0; +} + +static int tegra_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct colibri_t20_wm9715l *machine = snd_soc_card_get_drvdata(rtd->card); + + tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); + + return 0; +} + +static struct snd_soc_ops colibri_t20_wm9715l_ops = { + .hw_params = colibri_t20_wm9715l_hw_params, + .hw_free = tegra_hw_free, +}; + +static struct snd_soc_ops tegra_spdif_ops = { + .hw_params = tegra_spdif_hw_params, + .hw_free = tegra_hw_free, +}; + +static const struct snd_soc_dapm_widget colibri_t20_wm9715l_dapm_widgets[] = { + SND_SOC_DAPM_HP("HEADPHONE", NULL), + SND_SOC_DAPM_LINE("LINEIN", NULL), + SND_SOC_DAPM_MIC("MIC_IN", NULL), +}; + +/* Currently supported audio map */ +static const struct snd_soc_dapm_route colibri_t20_wm9715l_audio_map[] = { + /* Colibri SODIMM pin 1 (MIC_IN) + Colibri Evaluation Board: Audio jack X26 bottom pink + Iris: Audio header X9 pin 2 + Orchid: Audio jack X11 bottom pink MIC in */ + { "MIC_IN", NULL, "MIC1" }, + + /* Colibri SODIMM pin 5 & 7 (LINEIN_L/R) + Colibri Evaluation Board: Audio jack X26 top blue + Iris: Audio header X9 pin 4 & 3 + MECS Tellurium: Audio jack X11 pin 1 & 2 + Orchid: Audio jack X11 top blue line in */ + { "LINEIN", NULL, "LINEINL" }, + { "LINEIN", NULL, "LINEINR" }, + + /* Colibri SODIMM pin 15 & 17 (HEADPHONE_L/R) + Colibri Evaluation Board: Audio jack X26 middle green + Iris: Audio jack X8 + MECS Tellurium: Audio jack X11 pin 4 & 5 (HEADPHONE_LF/RF) + Orchid: Audio jack X11 middle green line out + Protea: Audio jack X53 line out */ + { "HEADPHONE", NULL, "LOUT2" }, + { "HEADPHONE", NULL, "ROUT2" }, +}; + +static int colibri_t20_wm9715l_init(struct snd_soc_pcm_runtime *rtd) +{ + int err; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + + pr_info("%s()\n", __func__); + +//GPIOs + + /* add Colibri T20 specific widgets */ + err = snd_soc_dapm_new_controls(dapm, colibri_t20_wm9715l_dapm_widgets, + ARRAY_SIZE(colibri_t20_wm9715l_dapm_widgets)); + if (err) + return err; + + /* set up Colibri T20 specific audio path audio_map */ + err = snd_soc_dapm_add_routes(dapm, colibri_t20_wm9715l_audio_map, ARRAY_SIZE(colibri_t20_wm9715l_audio_map)); + if (err) + return err; + +//jack detection + + /* connected pins */ + snd_soc_dapm_enable_pin(dapm, "HPOUTL"); + snd_soc_dapm_enable_pin(dapm, "HPOUTR"); + snd_soc_dapm_enable_pin(dapm, "LINEINL"); + snd_soc_dapm_enable_pin(dapm, "LINEINR"); + snd_soc_dapm_enable_pin(dapm, "MIC1"); + + /* Activate Mic Bias */ + snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); + + /* not connected pins */ + snd_soc_dapm_nc_pin(dapm, "LOUT2"); + snd_soc_dapm_nc_pin(dapm, "MIC2"); + snd_soc_dapm_nc_pin(dapm, "MONOOUT"); + snd_soc_dapm_nc_pin(dapm, "OUT3"); + snd_soc_dapm_nc_pin(dapm, "PCBEEP"); + snd_soc_dapm_nc_pin(dapm, "PHONE"); + snd_soc_dapm_nc_pin(dapm, "ROUT2"); + + err = snd_soc_dapm_sync(dapm); + if (err) + return err; + + return 0; +} + +static struct snd_soc_dai_link colibri_t20_wm9715l_dai[] = { + { + .name = "AC97", +// .name = "AC97 HiFi", + .stream_name = "AC97 HiFi", + .cpu_dai_name = "tegra20-ac97-pcm", + .codec_dai_name = "wm9712-hifi", + .platform_name = "tegra-pcm-audio", + .codec_name = "wm9712-codec", + .init = colibri_t20_wm9715l_init, + .ops = &colibri_t20_wm9715l_ops, + }, +//order + { + .name = "SPDIF", + .stream_name = "SPDIF PCM", + .codec_name = "spdif-dit.0", + .platform_name = "tegra-pcm-audio", + .cpu_dai_name = "tegra20-spdif", + .codec_dai_name = "dit-hifi", + .ops = &tegra_spdif_ops, + }, +#if 0 + { + .name = "AC97 Aux", + .stream_name = "AC97 Aux", + .cpu_dai_name = "tegra20-ac97-modem", + .codec_dai_name = "wm9712-aux", + .platform_name = "tegra-pcm-audio", + .codec_name = "wm9712-codec", + }, +#endif +}; + +//power management + +static struct snd_soc_card snd_soc_colibri_t20_wm9715l = { + .name = "colibri_t20-wm9715l", + .dai_link = colibri_t20_wm9715l_dai, + .num_links = ARRAY_SIZE(colibri_t20_wm9715l_dai), +// .suspend_post = colibri_t20_wm9715l_suspend_post, +// .resume_pre = colibri_t20_wm9715l_resume_pre, +}; + +// +static struct platform_device *colibri_t20_snd_wm9715l_device; + +static __devinit int colibri_t20_wm9715l_driver_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_colibri_t20_wm9715l; + struct colibri_t20_wm9715l *machine; + int ret; + + pr_info("%s()\n", __func__); + + if (!machine_is_colibri_t20()) + return -ENODEV; + +//make sure tegra20-ac97 is properly loaded to avoid subsequent crash + + machine = kzalloc(sizeof(struct colibri_t20_wm9715l), GFP_KERNEL); + if (!machine) { + dev_err(&pdev->dev, "Can't allocate colibri_t20_wm9715l struct\n"); + return -ENOMEM; + } + + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); + if (ret) + goto err_free_machine; + +//regulator handling + +//switch handling + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + + /* explicitly instanciate AC97 codec */ + colibri_t20_snd_wm9715l_device = platform_device_alloc("wm9712-codec", -1); + if (!colibri_t20_snd_wm9715l_device) { + dev_err(&pdev->dev, "platform_device_alloc of wm9712-codec failed (%d)\n", + ret); + goto err_fini_utils; + } + + ret = platform_device_add(colibri_t20_snd_wm9715l_device); + if (ret) { + dev_err(&pdev->dev, "platform_device_add of wm9712-codec failed (%d)\n", + ret); + goto err_device_put; + } + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_device_del; + } + + if (!card->instantiated) { + ret = -ENODEV; + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_unregister_card; + } + + return 0; + +err_unregister_card: + snd_soc_unregister_card(card); +err_device_del: + platform_device_del(colibri_t20_snd_wm9715l_device); +err_device_put: + platform_device_put(colibri_t20_snd_wm9715l_device); +err_fini_utils: + tegra_asoc_utils_fini(&machine->util_data); +err_free_machine: + kfree(machine); + return ret; +} + +static int __devexit colibri_t20_wm9715l_driver_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct colibri_t20_wm9715l *machine = snd_soc_card_get_drvdata(card); + + snd_soc_unregister_card(card); + + platform_device_unregister(colibri_t20_snd_wm9715l_device); + + tegra_asoc_utils_fini(&machine->util_data); + + kfree(machine); + + return 0; +} + +static struct platform_driver colibri_t20_wm9715l_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +// .pm = &snd_soc_pm_ops, + }, + .probe = colibri_t20_wm9715l_driver_probe, + .remove = __devexit_p(colibri_t20_wm9715l_driver_remove), +}; + +static int __init colibri_t20_wm9715l_modinit(void) +{ + return platform_driver_register(&colibri_t20_wm9715l_driver); +} + +static void __exit colibri_t20_wm9715l_modexit(void) +{ + platform_driver_unregister(&colibri_t20_wm9715l_driver); +} + +module_init(colibri_t20_wm9715l_modinit); +module_exit(colibri_t20_wm9715l_modexit); + +/* Module information */ +MODULE_AUTHOR("Marcel Ziswiler <marcel.ziswiler@toradex.com>"); +MODULE_DESCRIPTION("ALSA SoC WM9715L on Toradex Colibri T20"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/tegra/colibri_t30.c b/sound/soc/tegra/colibri_t30.c new file mode 100644 index 000000000000..6390be5b8d6b --- /dev/null +++ b/sound/soc/tegra/colibri_t30.c @@ -0,0 +1,412 @@ +/* + * SoC audio driver for Toradex Colibri T30 + * + * Copyright (C) 2012 Toradex Inc. + * + * 2012-02-12: Marcel Ziswiler <marcel.ziswiler@toradex.com> + * initial version + * + * Copied from tegra_wm8903.c + * Copyright (C) 2010-2011 - NVIDIA, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <asm/mach-types.h> + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <mach/tegra_asoc_pdata.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "../codecs/sgtl5000.h" + +#include "tegra_pcm.h" +#include "tegra_asoc_utils.h" + +#define DRV_NAME "tegra-snd-colibri_t30-sgtl5000" + +struct colibri_t30_sgtl5000 { + struct tegra_asoc_utils_data util_data; + struct tegra_asoc_platform_data *pdata; + enum snd_soc_bias_level bias_level; +}; + +static int colibri_t30_sgtl5000_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = codec->card; + struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(card); + struct tegra_asoc_platform_data *pdata = machine->pdata; + int srate, mclk, i2s_daifmt; + int err; + int rate; + + /* sgtl5000 does not support 512*rate when in 96000 fs */ + srate = params_rate(params); + switch (srate) { + case 96000: + mclk = 256 * srate; + break; + default: + mclk = 512 * srate; + break; + } + + /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */ + if (mclk < 8000000 || mclk > 27000000) + return -EINVAL; + + if(pdata->i2s_param[HIFI_CODEC].is_i2s_master) { + i2s_daifmt = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + } else { + i2s_daifmt = SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + } + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + if (!(machine->util_data.set_mclk % mclk)) + mclk = machine->util_data.set_mclk; + else { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + } + + tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); + + rate = clk_get_rate(machine->util_data.clk_cdev1); + + /* Use DSP mode for mono on Tegra20 */ + if (params_channels(params) != 2) { + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + } else { + switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { + case TEGRA_DAIFMT_I2S : + i2s_daifmt |= SND_SOC_DAIFMT_I2S; + break; + case TEGRA_DAIFMT_DSP_A : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; + break; + case TEGRA_DAIFMT_DSP_B : + i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; + break; + case TEGRA_DAIFMT_LEFT_J : + i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; + break; + case TEGRA_DAIFMT_RIGHT_J : + i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; + break; + default : + dev_err(card->dev, + "Can't configure i2s format\n"); + return -EINVAL; + } + } + + err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); + if (err < 0) { + dev_err(card->dev, "codec_dai fmt not set\n"); + return err; + } + + err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); + if (err < 0) { + dev_err(card->dev, "cpu_dai fmt not set\n"); + return err; + } + + /* Set SGTL5000's SYSCLK (provided by clk_out_1) */ + err = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, rate, SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return err; + } + + return 0; +} + +static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(card); + int srate, mclk, min_mclk; + int err; + + srate = params_rate(params); + switch (srate) { + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + case 8000: + case 16000: + case 32000: + case 48000: + case 64000: + case 96000: + mclk = 12288000; + break; + default: + return -EINVAL; + } + min_mclk = 128 * srate; + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + if (!(machine->util_data.set_mclk % min_mclk)) + mclk = machine->util_data.set_mclk; + else { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + } + + tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); + + return 0; +} + +static int tegra_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(rtd->card); + + tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); + + return 0; +} + +static struct snd_soc_ops colibri_t30_sgtl5000_ops = { + .hw_params = colibri_t30_sgtl5000_hw_params, + .hw_free = tegra_hw_free, +}; + +static struct snd_soc_ops tegra_spdif_ops = { + .hw_params = tegra_spdif_hw_params, + .hw_free = tegra_hw_free, +}; + +/* Colibri T30 machine DAPM widgets */ +static const struct snd_soc_dapm_widget colibri_t30_sgtl5000_dapm_widgets[] = { + SND_SOC_DAPM_HP("HEADPHONE", NULL), + SND_SOC_DAPM_LINE("LINEIN", NULL), + SND_SOC_DAPM_MIC("MIC_IN", NULL), +}; + +/* Colibri T30 machine audio map (connections to the codec pins) */ +static const struct snd_soc_dapm_route colibri_t30_sgtl5000_dapm_route[] = { + /* Colibri SODIMM pin 1 (MIC_IN) + Colibri Evaluation Board: Audio jack X26 bottom pink + Iris: Audio header X9 pin 2 + Orchid: Audio jack X11 bottom pink MIC in */ +//mic bias GPIO handling +// [ 9.359733] tegra-snd-colibri_t30-sgtl5000 tegra-snd-colibri_t30-sgtl5000.0: Failed to add route MICIN->MIC_IN +// { "MIC_IN", NULL, "MIC_IN" }, + + /* Colibri SODIMM pin 5 & 7 (LINEIN_L/R) + Colibri Evaluation Board: Audio jack X26 top blue + Iris: Audio header X9 pin 4 & 3 + MECS Tellurium: Audio jack X11 pin 1 & 2 + Orchid: Audio jack X11 top blue line in */ + { "LINEIN", NULL, "LINE_IN" }, + + /* Colibri SODIMM pin 15 & 17 (HEADPHONE_L/R) + Colibri Evaluation Board: Audio jack X26 middle green + Iris: Audio jack X8 + MECS Tellurium: Audio jack X11 pin 4 & 5 (HEADPHONE_LF/RF) + Orchid: Audio jack X11 middle green line out + Protea: Audio jack X53 line out */ +//HP PGA handling + { "HEADPHONE", NULL, "HP_OUT" }, +}; + +static int colibri_t30_sgtl5000_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_card *card = codec->card; + struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(card); + int ret; + + machine->bias_level = SND_SOC_BIAS_STANDBY; + + ret = tegra_asoc_utils_register_ctls(&machine->util_data); + if (ret < 0) + return ret; + + snd_soc_dapm_nc_pin(dapm, "LINE_OUT"); + + snd_soc_dapm_sync(dapm); + + return 0; +} + +static struct snd_soc_dai_link colibri_t30_sgtl5000_dai[] = { + { + .name = "SGTL5000", + .stream_name = "SGTL5000 PCM", + .codec_name = "sgtl5000.4-000a", + .platform_name = "tegra-pcm-audio", + .cpu_dai_name = "tegra30-i2s.2", + .codec_dai_name = "sgtl5000", + .init = colibri_t30_sgtl5000_init, + .ops = &colibri_t30_sgtl5000_ops, + }, + { + .name = "SPDIF", + .stream_name = "SPDIF PCM", + .codec_name = "spdif-dit.0", + .platform_name = "tegra-pcm-audio", + .cpu_dai_name = "tegra30-spdif", + .codec_dai_name = "dit-hifi", + .ops = &tegra_spdif_ops, + }, +}; + +static struct snd_soc_card snd_soc_colibri_t30_sgtl5000 = { + .name = "colibri_t30-sgtl5000", + .dai_link = colibri_t30_sgtl5000_dai, + .num_links = ARRAY_SIZE(colibri_t30_sgtl5000_dai), +// .set_bias_level +// .set_bias_level_post +}; + +static __devinit int colibri_t30_sgtl5000_driver_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_colibri_t30_sgtl5000; + struct colibri_t30_sgtl5000 *machine; + struct tegra_asoc_platform_data *pdata; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "No platform data supplied\n"); + return -EINVAL; + } + + machine = kzalloc(sizeof(struct colibri_t30_sgtl5000), GFP_KERNEL); + if (!machine) { + dev_err(&pdev->dev, "Can't allocate colibri_t30_sgtl5000 struct\n"); + return -ENOMEM; + } + + machine->pdata = pdata; + + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); + if (ret) + goto err_free_machine; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + + card->dapm_widgets = colibri_t30_sgtl5000_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(colibri_t30_sgtl5000_dapm_widgets); + + card->dapm_routes = colibri_t30_sgtl5000_dapm_route; + card->num_dapm_routes = ARRAY_SIZE(colibri_t30_sgtl5000_dapm_route); + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_fini_utils; + } + + if (!card->instantiated) { + ret = -ENODEV; + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_unregister_card; + } + + ret = tegra_asoc_utils_set_parent(&machine->util_data, + pdata->i2s_param[HIFI_CODEC].is_i2s_master); + if (ret) { + dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n", + ret); + goto err_unregister_card; + } + + return 0; + +err_unregister_card: + snd_soc_unregister_card(card); +err_fini_utils: + tegra_asoc_utils_fini(&machine->util_data); +err_free_machine: + kfree(machine); + return ret; +} + +static int __devexit colibri_t30_sgtl5000_driver_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(card); + + snd_soc_unregister_card(card); + + tegra_asoc_utils_fini(&machine->util_data); + + kfree(machine); + + return 0; +} + +static struct platform_driver colibri_t30_sgtl5000_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = colibri_t30_sgtl5000_driver_probe, + .remove = __devexit_p(colibri_t30_sgtl5000_driver_remove), +}; + +static int __init colibri_t30_sgtl5000_modinit(void) +{ + return platform_driver_register(&colibri_t30_sgtl5000_driver); +} +module_init(colibri_t30_sgtl5000_modinit); + +static void __exit colibri_t30_sgtl5000_modexit(void) +{ + platform_driver_unregister(&colibri_t30_sgtl5000_driver); +} +module_exit(colibri_t30_sgtl5000_modexit); + +/* Module information */ +MODULE_AUTHOR("Marcel Ziswiler <marcel.ziswiler@toradex.com>"); +MODULE_DESCRIPTION("ALSA SoC SGTL5000 on Toradex Colibri T30"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c new file mode 100644 index 000000000000..9b7ddb667860 --- /dev/null +++ b/sound/soc/tegra/tegra20_ac97.c @@ -0,0 +1,651 @@ +/* + * sound/soc/tegra/tegra20_ac97.c + * + * Copyright (C) 2012 Toradex, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <mach/ac97.h> +#include <mach/audio.h> +#include <mach/dma.h> +#include <mach/gpio.h> +#include <mach/iomap.h> + +#include <sound/ac97_codec.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm_params.h> +#include <sound/pcm.h> +#include <sound/soc.h> + +#include "../../../arch/arm/mach-tegra/gpio-names.h" +#include "tegra_pcm.h" +#include "tegra20_ac97.h" +#include "tegra20_das.h" + +#define DRV_NAME "tegra20-ac97" + +//required? +static DEFINE_MUTEX(car_mutex); + +#define check_ifc(n, ...) if ((n) > TEGRA_DAI_AC97_MODEM) { \ + pr_err("%s: invalid AC97 interface %d\n", __func__, (n)); \ + return __VA_ARGS__; \ +} + +/* required due to AC97 codec drivers not adhering to proper platform driver + model */ +static struct tegra20_ac97 *ac97; + +static int tegra20_ac97_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ +pr_info("%s %u fmt=%d", __func__, __LINE__, fmt); + return 0; +} + +phys_addr_t ac97_get_fifo_phy_base(struct tegra20_ac97 *ac97, int ifc, int fifo) +{ + check_ifc(ifc, 0); + + if (ifc == TEGRA_DAI_AC97_PCM) + return (phys_addr_t)ac97->phys + (fifo ? AC_AC_FIFO_IN1_0 : AC_AC_FIFO_OUT1_0); + else + return (phys_addr_t)ac97->phys + (fifo ? AC_AC_FIFO_IN2_0 : AC_AC_FIFO_OUT2_0); +} + +static int tegra20_ac97_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); + + pr_info("%s(): dai->id=%d, %s\n", __func__, dai->id, (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)?"play":"rec"); + +//TODO: adaptable sample size + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ac97->playback_dma_data.addr = + ac97_get_fifo_phy_base(ac97, dai->id, AC97_FIFO_TX); + ac97->playback_dma_data.wrap = 4; + ac97->playback_dma_data.width = 32; + } else { + ac97->capture_dma_data.addr = + ac97_get_fifo_phy_base(ac97, dai->id, AC97_FIFO_RX); + ac97->capture_dma_data.wrap = 4; + ac97->capture_dma_data.width = 32; + } + + return 0; +} + +int ac97_fifo_set_attention_level(struct tegra20_ac97 *ac97, int ifc, int fifo, unsigned level) +{ + u32 val; + + pr_info("%s()\n", __func__); + + check_ifc(ifc, -EINVAL); + + if (ifc == TEGRA_DAI_AC97_PCM) + val = readl(ac97->regs + AC_AC_FIFO1_SCR_0); + else + val = readl(ac97->regs + AC_AC_FIFO2_SCR_0); + + if (fifo) { + val &= ~(AC_AC_FIFOx_SCR_REC_FIFOx_FULL_EN | + AC_AC_FIFOx_SCR_REC_FIFOx_3QRT_FULL_EN | + AC_AC_FIFOx_SCR_REC_FIFOx_QRT_FULL_EN | + AC_AC_FIFOx_SCR_REC_FIFOx_NOT_MT_EN); + switch (level) { + case AC97_FIFO_ATN_LVL_NONE: + break; + case AC97_FIFO_ATN_LVL_FULL: + val |= AC_AC_FIFOx_SCR_REC_FIFOx_FULL_EN; + break; + case AC97_FIFO_ATN_LVL_3QUART: + val |= AC_AC_FIFOx_SCR_REC_FIFOx_3QRT_FULL_EN; + break; + case AC97_FIFO_ATN_LVL_QUART: + val |= AC_AC_FIFOx_SCR_REC_FIFOx_QRT_FULL_EN; + break; + case AC97_FIFO_ATN_LVL_EMPTY: + val |= AC_AC_FIFOx_SCR_REC_FIFOx_NOT_MT_EN; + break; + default: + pr_err("%s: invalid FIFO level selector %d\n", __func__, + level); + return -EINVAL; + } + } + else { + val &= ~(AC_AC_FIFOx_SCR_PB_FIFOx_NOT_FULL_EN | + AC_AC_FIFOx_SCR_PB_FIFOx_QRT_MT_EN | + AC_AC_FIFOx_SCR_PB_FIFOx_3QRT_MT_EN | + AC_AC_FIFOx_SCR_PB_FIFOx_MT_EN); + switch (level) { + case AC97_FIFO_ATN_LVL_NONE: + break; + case AC97_FIFO_ATN_LVL_FULL: + val |= AC_AC_FIFOx_SCR_PB_FIFOx_NOT_FULL_EN; + break; + case AC97_FIFO_ATN_LVL_3QUART: + val |= AC_AC_FIFOx_SCR_PB_FIFOx_3QRT_MT_EN; + break; + case AC97_FIFO_ATN_LVL_QUART: + val |= AC_AC_FIFOx_SCR_PB_FIFOx_QRT_MT_EN; + break; + case AC97_FIFO_ATN_LVL_EMPTY: + val |= AC_AC_FIFOx_SCR_PB_FIFOx_MT_EN; + break; + default: + pr_err("%s: invalid FIFO level selector %d\n", __func__, + level); + return -EINVAL; + } + } + + if (ifc == TEGRA_DAI_AC97_PCM) + writel(val, ac97->regs + AC_AC_FIFO1_SCR_0); + else + writel(val, ac97->regs + AC_AC_FIFO2_SCR_0); + + return 0; +} + +void ac97_slot_enable(struct tegra20_ac97 *ac97, int ifc, int fifo, int on) +{ + pr_info("%s()\n", __func__); + + check_ifc(ifc); + + if (!fifo) { + u32 val; + + val = readl(ac97->regs + AC_AC_CTRL_0); + + if (ifc == TEGRA_DAI_AC97_PCM) + if (on) { +#ifndef TEGRA_AC97_32BIT_PLAYBACK + /* Enable packed mode for now */ + val |= AC_AC_CTRL_STM_EN; +#endif + val |= AC_AC_CTRL_PCM_DAC_EN; + } else + val &= ~AC_AC_CTRL_PCM_DAC_EN; + else + if (on) { +#ifndef TEGRA_AC97_32BIT_PLAYBACK + /* Enable packed mode for now */ + val |= AC_AC_CTRL_STM2_EN; +#endif + val |= AC_AC_CTRL_LINE1_DAC_EN; + } else + val &= ~AC_AC_CTRL_LINE1_DAC_EN; + + writel(val, ac97->regs + AC_AC_CTRL_0); + } +} + +/* playback */ +static inline void tegra20_ac97_start_playback(struct snd_soc_dai *cpu_dai) +{ + struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(cpu_dai); + + pr_info("%s()\n", __func__); + + ac97_fifo_set_attention_level(ac97, cpu_dai->id, AC97_FIFO_TX, + /* Only FIFO level proven stable for video playback */ +#ifdef TEGRA_AC97_32BIT_PLAYBACK + AC97_FIFO_ATN_LVL_QUART); +#else + AC97_FIFO_ATN_LVL_EMPTY); +#endif + ac97_slot_enable(ac97, cpu_dai->id, AC97_FIFO_TX, 1); +} + +static inline void tegra20_ac97_stop_playback(struct snd_soc_dai *cpu_dai) +{ + struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(cpu_dai); + int delay_cnt = 10; /* 1ms max wait for fifo to drain */ + + pr_info("%s()\n", __func__); + + ac97_fifo_set_attention_level(ac97, cpu_dai->id, AC97_FIFO_TX, + AC97_FIFO_ATN_LVL_NONE); + +//something wrong? + while (!(readl(ac97->regs + AC_AC_CTRL_0) & + AC_AC_FIFOx_SCR_PB_FIFOx_UNDERRUN_INT_STA) && + delay_cnt) + { + udelay(100); + delay_cnt--; + } + + ac97_slot_enable(ac97, cpu_dai->id, AC97_FIFO_TX, 0); +} + +/* recording */ +static inline void tegra20_ac97_start_capture(struct snd_soc_dai *cpu_dai) +{ + struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(cpu_dai); +//check slot validity in received tag information + ac97_fifo_set_attention_level(ac97, cpu_dai->id, AC97_FIFO_RX, + AC97_FIFO_ATN_LVL_FULL); +} + +static inline void tegra20_ac97_stop_capture(struct snd_soc_dai *cpu_dai) +{ + struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(cpu_dai); + ac97_fifo_set_attention_level(ac97, cpu_dai->id, AC97_FIFO_RX, + AC97_FIFO_ATN_LVL_NONE); + +//wait? +} + +static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int ret = 0; + + pr_info("%s()\n", __func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tegra20_ac97_start_playback(dai); + else + tegra20_ac97_start_capture(dai); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tegra20_ac97_stop_playback(dai); + else + tegra20_ac97_stop_capture(dai); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static void tegra20_ac97_reset(struct snd_ac97 *ac97) +{ + int gpio_status; + + pr_info("%s()\n", __func__); + + /* do wolfson hard reset */ +#define GPIO_AC97_nRESET TEGRA_GPIO_PV0 + gpio_status = gpio_request(GPIO_AC97_nRESET, "WOLFSON_RESET"); + if (gpio_status < 0) { + pr_info("WOLFSON_RESET request GPIO FAILED\n"); + WARN_ON(1); + } + gpio_status = gpio_direction_output(GPIO_AC97_nRESET, 0); + if (gpio_status < 0) { + pr_info("WOLFSON_RESET request GPIO DIRECTION FAILED\n"); + WARN_ON(1); + } + udelay(2); + gpio_set_value(GPIO_AC97_nRESET, 1); + udelay(2); +} + +static void tegra20_ac97_warm_reset(struct snd_ac97 *ac97) +{ + int gpio_status; + + pr_info("%s()\n", __func__); + + /* do wolfson warm reset by toggling SYNC */ +#define GPIO_AC97_SYNC TEGRA_GPIO_PP0 + gpio_status = gpio_request(GPIO_AC97_SYNC, "WOLFSON_SYNC"); + if (gpio_status < 0) { + pr_info("WOLFSON_SYNC request GPIO FAILED\n"); + WARN_ON(1); + } + gpio_status = gpio_direction_output(GPIO_AC97_SYNC, 1); + if (gpio_status < 0) { + pr_info("WOLFSON_SYNC request GPIO DIRECTION FAILED\n"); + WARN_ON(1); + } + udelay(2); + gpio_set_value(GPIO_AC97_SYNC, 0); + udelay(2); + gpio_free(GPIO_AC97_SYNC); +} + +static unsigned short tegra20_ac97_read(struct snd_ac97 *ac97_snd, unsigned short reg) +{ +// struct tegra20_ac97 *ac97 = ac97_snd->private_data; + u32 val; + int timeout = 100; + +//pr_info("%s(0x%04x)", __func__, reg); + +// mutex_lock(&car_mutex); + + /* Set MSB=1 to indicate Read Command! */ + writel((((reg | 0x80) << AC_AC_CMD_CMD_ADDR_SHIFT) & + AC_AC_CMD_CMD_ADDR_MASK) | + /* Set Busy Bit to start Command!! */ + AC_AC_CMD_BUSY, ac97->regs + AC_AC_CMD_0); + + while (!((val = readl(ac97->regs + AC_AC_STATUS1_0)) & + AC_AC_STATUS1_STA_VALID1) && timeout--) + mdelay(1); + +// mutex_unlock(&car_mutex); + +//pr_info(" = 0x%04x\n", (val & AC_AC_STATUS1_STA_DATA1_MASK) >> AC_AC_STATUS1_STA_DATA1_SHIFT); + + return (val & AC_AC_STATUS1_STA_DATA1_MASK) >> + AC_AC_STATUS1_STA_DATA1_SHIFT; +} + +static void tegra20_ac97_write(struct snd_ac97 *ac97_snd, unsigned short reg, + unsigned short val) +{ +// struct tegra20_ac97 *ac97 = ac97_snd->private_data; + int timeout = 100; + +//pr_info("%s(0x%04x, 0x%04x)\n", __func__, reg, val); + +// mutex_lock(&car_mutex); + + writel(((reg << AC_AC_CMD_CMD_ADDR_SHIFT) & AC_AC_CMD_CMD_ADDR_MASK) | + ((val << AC_AC_CMD_CMD_DATA_SHIFT) & + AC_AC_CMD_CMD_DATA_MASK) | + /* Set Busy Bit to start Command!! */ + AC_AC_CMD_BUSY, ac97->regs + AC_AC_CMD_0); + + while (((val = readl(ac97->regs + AC_AC_CMD_0)) & + AC_AC_CMD_BUSY) && timeout--) + mdelay(1); + +// mutex_unlock(&car_mutex); +} + +/* required by sound/soc/codecs/wm9712.c */ +struct snd_ac97_bus_ops soc_ac97_ops = { + .read = tegra20_ac97_read, + .reset = tegra20_ac97_reset, + .warm_reset = tegra20_ac97_warm_reset, + .write = tegra20_ac97_write, +}; +EXPORT_SYMBOL_GPL(soc_ac97_ops); + +static struct snd_ac97_bus_ops tegra20_ac97_ops = { + .read = tegra20_ac97_read, + /* reset already done above */ + .write = tegra20_ac97_write, +}; + +static int tegra20_ac97_probe(struct snd_soc_dai *dai) +{ +//hw_probe: reset GPIO, clk_get, clk_enable, request_irq + struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai); + + pr_info("%s()\n", __func__); + pr_info("ac97->capture_dma_data=%p\n", &ac97->capture_dma_data); + pr_info("ac97->playback_dma_data=%p\n", &ac97->playback_dma_data); + + dai->capture_dma_data = &ac97->capture_dma_data; + dai->playback_dma_data = &ac97->playback_dma_data; + + return 0; +} + +//TODO: power management + +static struct snd_soc_dai_ops tegra20_ac97_dai_ops = { + .hw_params = tegra20_ac97_hw_params, +// + .set_fmt = tegra20_ac97_set_fmt, +// + .trigger = tegra20_ac97_trigger, +}; + +struct snd_soc_dai_driver tegra20_ac97_dai[] = { + { + .name = DRV_NAME "-pcm", +// .id = 0, + .probe = tegra20_ac97_probe, +//.resume + .playback = { +// .stream_name = "AC97 PCM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AC97_SAMPLE_RATES, +#ifndef TEGRA_AC97_32BIT_PLAYBACK + .formats = SNDRV_PCM_FMTBIT_S16_LE, +#else + .formats = SNDRV_PCM_FMTBIT_S32_LE, +#endif + }, + .capture = { +// .stream_name = "AC97 PCM Recording", + .channels_min = 1, + .channels_max = 2, + .rates = AC97_SAMPLE_RATES, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tegra20_ac97_dai_ops, + .symmetric_rates = 1, + }, +#if 0 + { + .name = DRV_NAME "-modem", +// .id = 1, + .playback = { + .stream_name = "AC97 Modem Playback", + .channels_min = 1, + .channels_max = 1, + .rates = AC97_SAMPLE_RATES, +#ifndef TEGRA_AC97_32BIT_PLAYBACK + .formats = SNDRV_PCM_FMTBIT_S16_LE, +#else + .formats = SNDRV_PCM_FMTBIT_S32_LE, +#endif + }, + .capture = { + .stream_name = "AC97 Modem Recording", + .channels_min = 1, + .channels_max = 1, + .rates = AC97_SAMPLE_RATES, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tegra20_ac97_dai_ops, + .symmetric_rates = 1, + }, +#endif +}; + +static __devinit int tegra20_ac97_platform_probe(struct platform_device *pdev) +{ + struct resource *mem, *memregion, *dmareq; + int ret; + struct snd_ac97_bus *ac97_bus; + + pr_info("%s()\n", __func__); + + ac97 = kzalloc(sizeof(struct tegra20_ac97), GFP_KERNEL); + if (!ac97) { + dev_err(&pdev->dev, "Can't allocate tegra20_ac97\n"); + ret = -ENOMEM; + goto exit; + } + dev_set_drvdata(&pdev->dev, ac97); + + ac97->clk_ac97 = clk_get(&pdev->dev, NULL); + if (IS_ERR(ac97->clk_ac97)) { + dev_err(&pdev->dev, "Can't retrieve AC97 clock\n"); + ret = PTR_ERR(ac97->clk_ac97); + goto err_free; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENODEV; + goto err_clk_put; + } + ac97->phys = mem->start; + + dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!dmareq) { + dev_err(&pdev->dev, "No DMA resource\n"); + ret = -ENODEV; + goto err_clk_put; + } + + memregion = request_mem_region(mem->start, resource_size(mem), + DRV_NAME); + if (!memregion) { + dev_err(&pdev->dev, "Memory region already claimed\n"); + ret = -EBUSY; + goto err_clk_put; + } + + ac97->regs = ioremap(mem->start, resource_size(mem)); + if (!ac97->regs) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err_release; + } + + ac97->capture_dma_data.req_sel = dmareq->start; + ac97->playback_dma_data.req_sel = dmareq->start; + + ret = snd_soc_register_dais(&pdev->dev, tegra20_ac97_dai, ARRAY_SIZE(tegra20_ac97_dai)); + if (ret) { + dev_err(&pdev->dev, "Could not register DAIs\n"); + goto err_unmap; + } + +//required? +#if 1 +//use 1 in order for actual card to get 0 which is used as default e.g. in Android +// ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + ret = snd_card_create(1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &ac97->card); + if (ret < 0) { + dev_err(&pdev->dev, "failed creating snd_card!\n"); + goto err_create; + } + + ac97->card->dev = &pdev->dev; + strncpy(ac97->card->driver, pdev->dev.driver->name, sizeof(ac97->card->driver)); +#endif + +pr_info("%s() %u\n", __func__, __LINE__); + /* put propper DAC to DAP DAS path in place */ + + ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC3, + TEGRA20_DAS_DAP_ID_3); + if (ret < 0) { + dev_err(&pdev->dev, "failed to set dap-dac path\n"); + goto err_create; + } + + ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_3, + TEGRA20_DAS_DAP_SEL_DAC3); + if (ret < 0) { + dev_err(&pdev->dev, "failed to set dac-dap path\n"); + goto err_create; + } + +pr_info("%s() %u\n", __func__, __LINE__); + ret = snd_ac97_bus(ac97->card, 0, &tegra20_ac97_ops, NULL, &ac97_bus); + if (ret) { + dev_err(&pdev->dev, "failed registerign ac97_bus!\n"); + goto err_create; + } + + return 0; + +err_create: + snd_card_free(ac97->card); +err_unmap: + iounmap(ac97->regs); +err_release: + release_mem_region(mem->start, resource_size(mem)); +err_clk_put: + clk_put(ac97->clk_ac97); +err_free: + kfree(ac97); +exit: +pr_info("%s() %u\n", __func__, __LINE__); + return ret; +} + +static int __devexit tegra20_ac97_platform_remove(struct platform_device *pdev) +{ + struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev); + struct resource *res; + + snd_card_free(ac97->card); + + snd_soc_unregister_dai(&pdev->dev); + + iounmap(ac97->regs); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + clk_put(ac97->clk_ac97); + + kfree(ac97); + + return 0; +} + +static struct platform_driver tegra20_ac97_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = tegra20_ac97_platform_probe, + .remove = __devexit_p(tegra20_ac97_platform_remove), +}; + +static int __init snd_tegra20_ac97_init(void) +{ + return platform_driver_register(&tegra20_ac97_driver); +} +module_init(snd_tegra20_ac97_init); + +static void __exit snd_tegra20_ac97_exit(void) +{ + platform_driver_unregister(&tegra20_ac97_driver); +} +module_exit(snd_tegra20_ac97_exit); + +MODULE_AUTHOR("Marcel Ziswiler <marcel.ziswiler@toradex.com>"); +MODULE_DESCRIPTION("Tegra AC97 ASoC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/tegra/tegra20_ac97.h b/sound/soc/tegra/tegra20_ac97.h new file mode 100644 index 000000000000..430ecc1500f4 --- /dev/null +++ b/sound/soc/tegra/tegra20_ac97.h @@ -0,0 +1,43 @@ +/* + * linux/sound/soc/tegra/tegra20_ac97.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _TEGRA_AC97_H +#define _TEGRA_AC97_H + +#include "tegra_pcm.h" + +/* Tegra DAI ID's */ +#define TEGRA_DAI_AC97_PCM 0 /* slot 3: PCM left channel */ + /* slot 4: PCM right channel */ +#define TEGRA_DAI_AC97_MODEM 1 /* slot 5: modem line 1 */ + + /* slot 11: touch panel digitizer data */ + +#define AC97_FIFO_ATN_LVL_NONE 0 +#define AC97_FIFO_ATN_LVL_EMPTY 1 +#define AC97_FIFO_ATN_LVL_QUART 2 +#define AC97_FIFO_ATN_LVL_3QUART 3 +#define AC97_FIFO_ATN_LVL_FULL 4 + +#define AC97_FIFO_TX 0 +#define AC97_FIFO_RX 1 + +#define AC97_SAMPLE_RATES SNDRV_PCM_RATE_8000_48000 + +/* AC97 controller */ +struct tegra20_ac97 { + struct clk *dap_mclk; + struct clk *clk_ac97; + struct snd_card *card; + struct tegra_pcm_dma_params capture_dma_data; + phys_addr_t phys; + struct tegra_pcm_dma_params playback_dma_data; + void __iomem *regs; +}; + +#endif diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index a7c9c0a110f9..8bd0af7df610 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -42,6 +42,12 @@ #define DRV_NAME "tegra-pcm-audio" +#ifdef CONFIG_SND_SOC_TEGRA20_AC97 +/* AC97 capture conversion buffer pointers and sizes */ +static uint *conv_buf[MAX_DMA_REQ_COUNT]; +static uint conv_size[MAX_DMA_REQ_COUNT]; +#endif /* CONFIG_SND_SOC_TEGRA20_AC97 */ + static const struct snd_pcm_hardware tegra_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -67,22 +73,28 @@ static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd) unsigned long addr; dma_req = &prtd->dma_req[prtd->dma_req_idx]; - if (++prtd->dma_req_idx >= prtd->dma_req_count) - prtd->dma_req_idx -= prtd->dma_req_count; if (prtd->avp_dma_addr) addr = prtd->avp_dma_addr + prtd->dma_pos; else addr = buf->addr + prtd->dma_pos; - prtd->dma_pos += dma_req->size; - if (prtd->dma_pos >= prtd->dma_pos_end) - prtd->dma_pos = 0; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dma_req->source_addr = addr; - else + else { +#ifdef CONFIG_SND_SOC_TEGRA20_AC97 + conv_buf[prtd->dma_req_idx] = (uint *)(buf->area + prtd->dma_pos); + conv_size[prtd->dma_req_idx] = dma_req->size; +#endif /* CONFIG_SND_SOC_TEGRA20_AC97 */ dma_req->dest_addr = addr; + } + + /* Do index and DMA position update last */ + if (++prtd->dma_req_idx >= prtd->dma_req_count) + prtd->dma_req_idx -= prtd->dma_req_count; + prtd->dma_pos += dma_req->size; + if (prtd->dma_pos >= prtd->dma_pos_end) + prtd->dma_pos = 0; tegra_dma_enqueue_req(prtd->dma_chan, dma_req); } @@ -100,6 +112,17 @@ static void dma_complete_callback(struct tegra_dma_req *req) return; } +#ifdef CONFIG_SND_SOC_TEGRA20_AC97 + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + while (conv_size[prtd->dma_req_idx]) { + /* Convert 20-bit AC97 sample to 32-bit */ + *conv_buf[prtd->dma_req_idx] <<= 12; + conv_buf[prtd->dma_req_idx]++; + conv_size[prtd->dma_req_idx]-=4; + } + } +#endif /* CONFIG_SND_SOC_TEGRA20_AC97 */ + if (++prtd->period_index >= runtime->periods) prtd->period_index = 0; |