diff --git a/projects/RPi/linux/linux.arm.conf b/projects/RPi/linux/linux.arm.conf index acb1024f58..48bfebf319 100644 --- a/projects/RPi/linux/linux.arm.conf +++ b/projects/RPi/linux/linux.arm.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 3.14.2 Kernel Configuration +# Linux/arm 3.15.0 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -14,6 +14,7 @@ CONFIG_ARCH_HAS_CPUFREQ=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_FIQ=y CONFIG_VECTORS_BASE=0xffff0000 # CONFIG_ARM_PATCH_PHYS_VIRT is not set @@ -51,7 +52,9 @@ CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE_SYSCTL=y CONFIG_FHANDLE=y +# CONFIG_USELIB is not set # CONFIG_AUDIT is not set +CONFIG_HAVE_ARCH_AUDITSYSCALL=y # # IRQ subsystem @@ -59,6 +62,8 @@ CONFIG_FHANDLE=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_IRQ_SHOW=y CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set CONFIG_IRQ_FORCED_THREADING=y CONFIG_KTIME_SCALAR=y CONFIG_GENERIC_CLOCKEVENTS=y @@ -136,6 +141,7 @@ CONFIG_ANON_INODES=y CONFIG_HAVE_UID16=y CONFIG_EXPERT=y # CONFIG_UID16 is not set +# CONFIG_SYSFS_SYSCALL is not set CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set @@ -163,10 +169,12 @@ CONFIG_SLUB_DEBUG=y # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set # CONFIG_PROFILING is not set CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set CONFIG_JUMP_LABEL=y +# CONFIG_UPROBES is not set # CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y CONFIG_ARCH_USE_BUILTIN_BSWAP=y @@ -206,7 +214,6 @@ CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y CONFIG_BASE_SMALL=0 -# CONFIG_SYSTEM_TRUSTED_KEYRING is not set CONFIG_MODULES=y # CONFIG_MODULE_FORCE_LOAD is not set CONFIG_MODULE_UNLOAD=y @@ -288,7 +295,7 @@ CONFIG_ARCH_BCM2708=y # CONFIG_ARCH_W90X900 is not set # CONFIG_ARCH_LPC32XX is not set # CONFIG_ARCH_PXA is not set -# CONFIG_ARCH_MSM_NODT is not set +# CONFIG_ARCH_MSM is not set # CONFIG_ARCH_SHMOBILE_LEGACY is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set @@ -300,7 +307,6 @@ CONFIG_ARCH_BCM2708=y # CONFIG_ARCH_EXYNOS is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP1 is not set -# CONFIG_GPIO_PCA953X is not set # CONFIG_PLAT_SPEAR is not set # @@ -326,7 +332,6 @@ CONFIG_CPU_TLB_V6=y CONFIG_CPU_HAS_ASID=y CONFIG_CPU_CP15=y CONFIG_CPU_CP15_MMU=y -CONFIG_CPU_USE_DOMAINS=y # # Processor Features @@ -554,6 +559,7 @@ CONFIG_IPV6_NDISC_NODETYPE=y # CONFIG_IPV6_MULTIPLE_TABLES is not set # CONFIG_IPV6_MROUTE is not set # CONFIG_NETWORK_SECMARK is not set +# CONFIG_NET_PTP_CLASSIFY is not set # CONFIG_NETWORK_PHY_TIMESTAMPING is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -764,6 +770,7 @@ CONFIG_BQL=y # CONFIG_CAN is not set # CONFIG_IRDA is not set CONFIG_BT=m +CONFIG_BT_6LOWPAN=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y # CONFIG_BT_BNEP is not set @@ -839,8 +846,6 @@ CONFIG_FW_LOADER_USER_HELPER=y # CONFIG_GENERIC_CPU_DEVICES is not set CONFIG_REGMAP=y CONFIG_REGMAP_I2C=m -CONFIG_REGMAP_SPI=m -CONFIG_REGMAP_MMIO=m CONFIG_DMA_SHARED_BUFFER=y CONFIG_DMA_CMA=y @@ -937,6 +942,7 @@ CONFIG_BCM2708_VCHIQ=y # # Intel MIC Card Driver # +# CONFIG_ECHO is not set # # SCSI device support @@ -1029,6 +1035,7 @@ CONFIG_PHYLIB=y # CONFIG_VITESSE_PHY is not set # CONFIG_SMSC_PHY is not set # CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM7XXX_PHY is not set # CONFIG_BCM87XX_PHY is not set # CONFIG_ICPLUS_PHY is not set # CONFIG_REALTEK_PHY is not set @@ -1103,13 +1110,12 @@ CONFIG_ATH9K_BTCOEX_SUPPORT=y CONFIG_ATH9K=m CONFIG_ATH9K_AHB=y # CONFIG_ATH9K_DEBUGFS is not set -# CONFIG_ATH9K_LEGACY_RATE_CONTROL is not set CONFIG_ATH9K_HTC=m # CONFIG_ATH9K_HTC_DEBUGFS is not set CONFIG_CARL9170=m CONFIG_CARL9170_LEDS=y CONFIG_CARL9170_WPC=y -# CONFIG_CARL9170_HWRNG is not set +CONFIG_CARL9170_HWRNG=y CONFIG_ATH6KL=m # CONFIG_ATH6KL_SDIO is not set CONFIG_ATH6KL_USB=m @@ -1165,6 +1171,7 @@ CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set # CONFIG_MWIFIEX is not set # CONFIG_CW1200 is not set +# CONFIG_RSI_91X is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -1280,11 +1287,9 @@ CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y # CONFIG_SERIAL_MAX3100 is not set # CONFIG_SERIAL_MAX310X is not set -# CONFIG_SERIAL_SH_SCI is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_SCCNXP is not set -# CONFIG_SERIAL_TIMBERDALE is not set # CONFIG_SERIAL_ALTERA_JTAGUART is not set # CONFIG_SERIAL_ALTERA_UART is not set # CONFIG_SERIAL_IFX6X60 is not set @@ -1298,7 +1303,7 @@ CONFIG_HW_RANDOM=y # CONFIG_HW_RANDOM_TIMERIOMEM is not set # CONFIG_HW_RANDOM_ATMEL is not set # CONFIG_HW_RANDOM_EXYNOS is not set -CONFIG_HW_RANDOM_BCM2708=y +# CONFIG_HW_RANDOM_BCM2708 is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set @@ -1378,6 +1383,7 @@ CONFIG_SPI_BCM2708=y # CONFIG_SPI_SPIDEV=y # CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPMI is not set # CONFIG_HSI is not set # @@ -1411,13 +1417,13 @@ CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_PL061 is not set # CONFIG_GPIO_RCAR is not set # CONFIG_GPIO_SCH311X is not set -# CONFIG_GPIO_TS5500 is not set # # I2C GPIO expanders: # # CONFIG_GPIO_MAX7300 is not set # CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set # CONFIG_GPIO_PCF857X is not set # CONFIG_GPIO_SX150X is not set # CONFIG_GPIO_ADP5588 is not set @@ -1479,7 +1485,6 @@ CONFIG_HWMON=y # CONFIG_SENSORS_AD7314 is not set # CONFIG_SENSORS_AD7414 is not set # CONFIG_SENSORS_AD7418 is not set -# CONFIG_SENSORS_ADCXX is not set # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -1499,16 +1504,34 @@ CONFIG_HWMON=y # CONFIG_SENSORS_F71805F is not set # CONFIG_SENSORS_F71882FG is not set # CONFIG_SENSORS_F75375S is not set -# CONFIG_SENSORS_G760A is not set -# CONFIG_SENSORS_G762 is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set # CONFIG_SENSORS_GPIO_FAN is not set # CONFIG_SENSORS_HIH6130 is not set -# CONFIG_SENSORS_HTU21 is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_JC42 is not set # CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_ADCXX is not set # CONFIG_SENSORS_LM63 is not set # CONFIG_SENSORS_LM70 is not set # CONFIG_SENSORS_LM73 is not set @@ -1522,32 +1545,17 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_LM93 is not set -# CONFIG_SENSORS_LTC4151 is not set -# CONFIG_SENSORS_LTC4215 is not set -# CONFIG_SENSORS_LTC4245 is not set -# CONFIG_SENSORS_LTC4261 is not set # CONFIG_SENSORS_LM95234 is not set # CONFIG_SENSORS_LM95241 is not set # CONFIG_SENSORS_LM95245 is not set -# CONFIG_SENSORS_MAX1111 is not set -# CONFIG_SENSORS_MAX16065 is not set -# CONFIG_SENSORS_MAX1619 is not set -# CONFIG_SENSORS_MAX1668 is not set -# CONFIG_SENSORS_MAX197 is not set -# CONFIG_SENSORS_MAX6639 is not set -# CONFIG_SENSORS_MAX6642 is not set -# CONFIG_SENSORS_MAX6650 is not set -# CONFIG_SENSORS_MAX6697 is not set -# CONFIG_SENSORS_MCP3021 is not set -# CONFIG_SENSORS_NCT6775 is not set -# CONFIG_SENSORS_NTC_THERMISTOR is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6775 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_PMBUS is not set # CONFIG_SENSORS_SHT15 is not set # CONFIG_SENSORS_SHT21 is not set -# CONFIG_SENSORS_SMM665 is not set # CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_EMC1403 is not set # CONFIG_SENSORS_EMC2103 is not set @@ -1556,6 +1564,8 @@ CONFIG_HWMON=y # CONFIG_SENSORS_SMSC47M192 is not set # CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set # CONFIG_SENSORS_ADS1015 is not set # CONFIG_SENSORS_ADS7828 is not set # CONFIG_SENSORS_ADS7871 is not set @@ -1613,10 +1623,11 @@ CONFIG_BCMA_POSSIBLE=y # # Multifunction device drivers # -# CONFIG_MFD_CORE is not set +CONFIG_MFD_CORE=m # CONFIG_MFD_AS3711 is not set # CONFIG_PMIC_ADP5520 is not set # CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_BCM590XX is not set # CONFIG_MFD_CROS_EC is not set # CONFIG_MFD_ASIC3 is not set # CONFIG_PMIC_DA903X is not set @@ -1644,6 +1655,8 @@ CONFIG_BCMA_POSSIBLE=y # CONFIG_MFD_VIPERBOARD is not set # CONFIG_MFD_RETU is not set # CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +CONFIG_MFD_RTSX_USB=m # CONFIG_MFD_RC5T583 is not set # CONFIG_MFD_SEC_CORE is not set # CONFIG_MFD_SI476X_CORE is not set @@ -1661,6 +1674,7 @@ CONFIG_BCMA_POSSIBLE=y # CONFIG_TPS6507X is not set # CONFIG_MFD_TPS65090 is not set # CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set # CONFIG_MFD_TPS6586X is not set # CONFIG_MFD_TPS65910 is not set # CONFIG_MFD_TPS65912 is not set @@ -1727,6 +1741,7 @@ CONFIG_IR_JVC_DECODER=m CONFIG_IR_SONY_DECODER=m CONFIG_IR_RC5_SZ_DECODER=m CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m CONFIG_IR_MCE_KBD_DECODER=m CONFIG_RC_DEVICES=y CONFIG_RC_ATI_REMOTE=m @@ -1736,6 +1751,7 @@ CONFIG_IR_REDRAT3=m CONFIG_IR_STREAMZAP=m CONFIG_IR_IGUANA=m CONFIG_IR_TTUSBIR=m +# CONFIG_IR_IMG is not set # CONFIG_RC_LOOPBACK is not set CONFIG_IR_GPIO_CIR=m CONFIG_MEDIA_USB_SUPPORT=y @@ -1748,7 +1764,6 @@ CONFIG_VIDEO_PVRUSB2_SYSFS=y CONFIG_VIDEO_PVRUSB2_DVB=y # CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set # CONFIG_VIDEO_HDPVR is not set -# CONFIG_VIDEO_TLG2300 is not set # CONFIG_VIDEO_USBVISION is not set # CONFIG_VIDEO_STK1160_COMMON is not set @@ -1759,10 +1774,8 @@ CONFIG_VIDEO_AU0828=m CONFIG_VIDEO_AU0828_V4L2=y CONFIG_VIDEO_CX231XX=m CONFIG_VIDEO_CX231XX_RC=y -# CONFIG_VIDEO_CX231XX_ALSA is not set CONFIG_VIDEO_CX231XX_DVB=m CONFIG_VIDEO_TM6000=m -# CONFIG_VIDEO_TM6000_ALSA is not set CONFIG_VIDEO_TM6000_DVB=m # @@ -1804,7 +1817,6 @@ CONFIG_DVB_USB_AZ6007=m CONFIG_DVB_USB_CE6230=m CONFIG_DVB_USB_EC168=m # CONFIG_DVB_USB_GL861 is not set -CONFIG_DVB_USB_IT913X=m CONFIG_DVB_USB_LME2510=m # CONFIG_DVB_USB_MXL111SF is not set CONFIG_DVB_USB_RTL28XXU=m @@ -1818,7 +1830,6 @@ CONFIG_DVB_B2C2_FLEXCOP_USB=m # CONFIG_VIDEO_EM28XX=m # CONFIG_VIDEO_EM28XX_V4L2 is not set -# CONFIG_VIDEO_EM28XX_ALSA is not set CONFIG_VIDEO_EM28XX_DVB=m CONFIG_VIDEO_EM28XX_RC=m @@ -2019,6 +2030,7 @@ CONFIG_DVB_TUNER_DIB0090=m # # SEC control devices for DVB-S # +CONFIG_DVB_DRX39XYJ=m CONFIG_DVB_LNBP21=m CONFIG_DVB_LNBP22=m CONFIG_DVB_ISL6421=m @@ -2027,7 +2039,6 @@ CONFIG_DVB_A8293=m CONFIG_DVB_LGS8GXX=m CONFIG_DVB_ATBM8830=m CONFIG_DVB_IX2505V=m -CONFIG_DVB_IT913X_FE=m CONFIG_DVB_M88RS2000=m CONFIG_DVB_AF9033=m @@ -2039,9 +2050,15 @@ CONFIG_DVB_AF9033=m # # Graphics support # + +# +# Direct Rendering Manager +# # CONFIG_DRM is not set -# CONFIG_VGASTATE is not set -# CONFIG_VIDEO_OUTPUT_CONTROL is not set + +# +# Frame buffer Devices +# CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set # CONFIG_FB_DDC is not set @@ -2068,6 +2085,7 @@ CONFIG_FB_BCM2708=y # CONFIG_FB_ARMCLCD is not set # CONFIG_FB_OPENCORES is not set # CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set # CONFIG_FB_SMSCUFX is not set # CONFIG_FB_UDL is not set # CONFIG_FB_GOLDFISH is not set @@ -2078,6 +2096,7 @@ CONFIG_FB_BCM2708=y # CONFIG_FB_SIMPLE is not set # CONFIG_EXYNOS_VIDEO is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_VGASTATE is not set # # Console display driver support @@ -2087,60 +2106,7 @@ CONFIG_FRAMEBUFFER_CONSOLE=y # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set # CONFIG_LOGO is not set -CONFIG_SOUND=y -# CONFIG_SOUND_OSS_CORE is not set -CONFIG_SND=m -CONFIG_SND_TIMER=m -CONFIG_SND_PCM=m -CONFIG_SND_DMAENGINE_PCM=m -CONFIG_SND_HWDEP=m -CONFIG_SND_RAWMIDI=m -CONFIG_SND_COMPRESS_OFFLOAD=m -CONFIG_SND_JACK=y -# CONFIG_SND_SEQUENCER is not set -# CONFIG_SND_MIXER_OSS is not set -# CONFIG_SND_PCM_OSS is not set -CONFIG_SND_HRTIMER=m -CONFIG_SND_DYNAMIC_MINORS=y -CONFIG_SND_MAX_CARDS=32 -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set -CONFIG_SND_VMASTER=y -# CONFIG_SND_RAWMIDI_SEQ is not set -# CONFIG_SND_OPL3_LIB_SEQ is not set -# CONFIG_SND_OPL4_LIB_SEQ is not set -# CONFIG_SND_SBAWE_SEQ is not set -# CONFIG_SND_EMU10K1_SEQ is not set -# CONFIG_SND_DRIVERS is not set -CONFIG_SND_ARM=y -# CONFIG_SND_ARMAACI is not set -CONFIG_SND_BCM2835=m -CONFIG_SND_SPI=y -CONFIG_SND_USB=y -CONFIG_SND_USB_AUDIO=m -CONFIG_SND_USB_UA101=m -CONFIG_SND_USB_CAIAQ=m -CONFIG_SND_USB_CAIAQ_INPUT=y -CONFIG_SND_USB_6FIRE=m -CONFIG_SND_USB_HIFACE=m -CONFIG_SND_SOC=m -CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y -# CONFIG_SND_ATMEL_SOC is not set -CONFIG_SND_BCM2708_SOC_I2S=m -CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m -CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m -CONFIG_SND_BCM2708_SOC_RPI_DAC=m -CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m -# CONFIG_SND_DESIGNWARE_I2S is not set -CONFIG_SND_SOC_I2C_AND_SPI=m -CONFIG_SND_SOC_PCM1794A=m -CONFIG_SND_SOC_PCM5102A=m -CONFIG_SND_SOC_PCM512x=m -CONFIG_SND_SOC_WM8804=m -# CONFIG_SND_SIMPLE_CARD is not set -# CONFIG_SOUND_PRIME is not set +# CONFIG_SOUND is not set # # HID support @@ -2162,7 +2128,7 @@ CONFIG_HID_AUREAL=y CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y -# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CP2112 is not set CONFIG_HID_CYPRESS=y # CONFIG_HID_DRAGONRISE is not set # CONFIG_HID_EMS_FF is not set @@ -2297,6 +2263,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=y # # USB Imaging devices @@ -2405,7 +2372,6 @@ CONFIG_USB_SERIAL_PL2303=m # CONFIG_USB_GADGET is not set CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set -# CONFIG_MMC_UNSAFE_RESUME is not set # CONFIG_MMC_CLKGATE is not set # @@ -2456,7 +2422,6 @@ CONFIG_LEDS_GPIO=y # CONFIG_LEDS_LT3593 is not set # CONFIG_LEDS_TCA6507 is not set # CONFIG_LEDS_LM355x is not set -# CONFIG_LEDS_OT200 is not set # CONFIG_LEDS_BLINKM is not set # @@ -2526,6 +2491,7 @@ CONFIG_RTC_DRV_DS1307=m # CONFIG_RTC_DRV_M41T93 is not set # CONFIG_RTC_DRV_M41T94 is not set # CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1347 is not set # CONFIG_RTC_DRV_DS1390 is not set # CONFIG_RTC_DRV_MAX6902 is not set # CONFIG_RTC_DRV_R9701 is not set @@ -2572,9 +2538,7 @@ CONFIG_DMADEVICES=y # CONFIG_AMBA_PL08X is not set # CONFIG_DW_DMAC_CORE is not set # CONFIG_DW_DMAC is not set -# CONFIG_TIMB_DMA is not set # CONFIG_PL330_DMA is not set -CONFIG_DMA_BCM2835=m CONFIG_DMA_BCM2708=m CONFIG_DMA_ENGINE=y CONFIG_DMA_VIRTUAL_CHANNELS=m @@ -2600,7 +2564,6 @@ CONFIG_STAGING=y # CONFIG_USBIP_CORE is not set CONFIG_W35UND=m # CONFIG_PRISM2_USB is not set -# CONFIG_ECHO is not set # CONFIG_COMEDI is not set # CONFIG_RTLLIB is not set CONFIG_R8712U=m @@ -2608,7 +2571,6 @@ CONFIG_R8712U=m CONFIG_RTS5139=m # CONFIG_RTS5139_DEBUG is not set # CONFIG_TRANZPORT is not set -# CONFIG_LINE6_USB is not set # CONFIG_USB_SERIAL_QUATECH2 is not set CONFIG_VT6656=m # CONFIG_USB_ENESTORAGE is not set @@ -2623,9 +2585,10 @@ CONFIG_VT6656=m # CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set CONFIG_STAGING_MEDIA=y CONFIG_DVB_AS102=m -# CONFIG_VIDEO_GO7007 is not set CONFIG_USB_MSI3101=m +CONFIG_MEDIA_TUNER_MSI001=m # CONFIG_USB_SN9C102 is not set +CONFIG_DVB_RTL2832_SDR=m CONFIG_LIRC_STAGING=y CONFIG_LIRC_IGORPLUGUSB=m # CONFIG_LIRC_IMON is not set @@ -2647,11 +2610,16 @@ CONFIG_LIRC_XBOX=m # CONFIG_DGRP is not set # CONFIG_LUSTRE_FS is not set # CONFIG_DGAP is not set +# CONFIG_GS_FPGABOOT is not set CONFIG_CLKDEV_LOOKUP=y # # Hardware Spinlock drivers # +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_EM_TIMER_STI is not set # CONFIG_MAILBOX is not set # CONFIG_IOMMU_SUPPORT is not set @@ -2676,8 +2644,9 @@ CONFIG_CLKDEV_LOOKUP=y # PHY Subsystem # # CONFIG_GENERIC_PHY is not set -# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set # CONFIG_POWERCAP is not set +# CONFIG_MCB is not set # # File systems @@ -2759,6 +2728,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_PROC_FS=y CONFIG_PROC_SYSCTL=y CONFIG_PROC_PAGE_MONITOR=y +CONFIG_KERNFS=y CONFIG_SYSFS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y @@ -2966,9 +2936,9 @@ CONFIG_PANIC_TIMEOUT=0 # CONFIG_LOCK_STAT is not set # CONFIG_DEBUG_ATOMIC_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_WRITECOUNT is not set # CONFIG_DEBUG_LIST is not set # CONFIG_DEBUG_SG is not set # CONFIG_DEBUG_NOTIFIERS is not set @@ -2979,6 +2949,7 @@ CONFIG_PANIC_TIMEOUT=0 # # CONFIG_PROVE_RCU_DELAY is not set # CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_TORTURE_TEST is not set # CONFIG_RCU_TORTURE_TEST is not set CONFIG_RCU_CPU_STALL_TIMEOUT=21 CONFIG_RCU_CPU_STALL_VERBOSE=y @@ -3179,6 +3150,7 @@ CONFIG_CRC32_SLICEBY8=y # CONFIG_CRC7 is not set CONFIG_LIBCRC32C=y # CONFIG_CRC8 is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set # CONFIG_RANDOM32_SELFTEST is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y @@ -3196,7 +3168,7 @@ CONFIG_XZ_DEC=y CONFIG_DECOMPRESS_GZIP=y CONFIG_ASSOCIATIVE_ARRAY=y CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y +CONFIG_HAS_IOPORT_MAP=y CONFIG_HAS_DMA=y CONFIG_DQL=y CONFIG_NLATTR=y diff --git a/projects/RPi/options b/projects/RPi/options index ced6ed123e..3c743b69ec 100644 --- a/projects/RPi/options +++ b/projects/RPi/options @@ -109,7 +109,7 @@ # Kernel to use. values can be: # default: default mainline kernel - LINUX="3.14" + LINUX="default" # use linux-next (latest rc) instead latest released version LINUX_NEXT="no" diff --git a/projects/RPi/patches/linux/linux-01-RPi_support.patch b/projects/RPi/patches/linux/linux-01-RPi_support.patch index f72dc9e4df..bc730e5d0f 100644 --- a/projects/RPi/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi/patches/linux/linux-01-RPi_support.patch @@ -1,7 +1,7 @@ -From dbed5d4762ba6834567faaca5e4e4b38a5ad454f Mon Sep 17 00:00:00 2001 +From beaa4adeae6ca9ad09d12d84e41e093291ef7c4b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/124] Main bcm2708 linux port +Subject: [PATCH 01/53] Main bcm2708 linux port Signed-off-by: popcornmix --- @@ -17,7 +17,7 @@ Signed-off-by: popcornmix arch/arm/mach-bcm2708/Makefile.boot | 3 + arch/arm/mach-bcm2708/armctrl.c | 208 ++++ arch/arm/mach-bcm2708/armctrl.h | 27 + - arch/arm/mach-bcm2708/bcm2708.c | 717 +++++++++++ + arch/arm/mach-bcm2708/bcm2708.c | 720 +++++++++++ arch/arm/mach-bcm2708/bcm2708.h | 49 + arch/arm/mach-bcm2708/bcm2708_gpio.c | 361 ++++++ arch/arm/mach-bcm2708/clock.c | 61 + @@ -56,7 +56,7 @@ Signed-off-by: popcornmix drivers/mmc/host/sdhci.h | 37 + drivers/tty/serial/amba-pl011.c | 2 +- include/linux/mmc/sdhci.h | 2 + - 51 files changed, 7789 insertions(+), 72 deletions(-) + 51 files changed, 7792 insertions(+), 72 deletions(-) create mode 100644 arch/arm/configs/bcmrpi_cutdown_defconfig create mode 100644 arch/arm/configs/bcmrpi_defconfig create mode 100644 arch/arm/configs/bcmrpi_emergency_defconfig @@ -97,10 +97,10 @@ Signed-off-by: popcornmix create mode 100644 drivers/mmc/host/sdhci-bcm2708.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 44298ad..3e91b1e 100644 +index db3c541..0e8b8df 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -379,6 +379,22 @@ config ARCH_AT91 +@@ -384,6 +384,22 @@ config ARCH_AT91 This enables support for systems based on Atmel AT91RM9200 and AT91SAM9* processors. @@ -123,7 +123,7 @@ index 44298ad..3e91b1e 100644 config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" select ARCH_REQUIRE_GPIOLIB -@@ -1053,6 +1069,7 @@ source "arch/arm/mach-virt/Kconfig" +@@ -1068,6 +1084,7 @@ source "arch/arm/plat-versatile/Kconfig" source "arch/arm/mach-vt8500/Kconfig" source "arch/arm/mach-w90x900/Kconfig" @@ -132,10 +132,10 @@ index 44298ad..3e91b1e 100644 source "arch/arm/mach-zynq/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index 0531da8..117fb79 100644 +index eab8ecb..34f5efb 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug -@@ -920,6 +920,14 @@ choice +@@ -916,6 +916,14 @@ choice options; the platform specific options are deprecated and will be soon removed. @@ -151,7 +151,7 @@ index 0531da8..117fb79 100644 config DEBUG_EXYNOS_UART diff --git a/arch/arm/Makefile b/arch/arm/Makefile -index 08a9ef5..755e9c2 100644 +index 41c1931..092cd25 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -143,6 +143,7 @@ textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 @@ -159,9 +159,9 @@ index 08a9ef5..755e9c2 100644 machine-$(CONFIG_ARCH_AT91) += at91 machine-$(CONFIG_ARCH_BCM) += bcm +machine-$(CONFIG_ARCH_BCM2708) += bcm2708 - machine-$(CONFIG_ARCH_BCM2835) += bcm2835 machine-$(CONFIG_ARCH_BERLIN) += berlin machine-$(CONFIG_ARCH_CLPS711X) += clps711x + machine-$(CONFIG_ARCH_CNS3XXX) += cns3xxx diff --git a/arch/arm/configs/bcmrpi_cutdown_defconfig b/arch/arm/configs/bcmrpi_cutdown_defconfig new file mode 100644 index 0000000..74f2dc9 @@ -1697,12 +1697,12 @@ index 0000000..3b40c49 +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c -index 92f7b15..7b5ed03 100644 +index 81ef686..c5ed46f 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c -@@ -176,6 +176,16 @@ void arch_cpu_idle(void) - default_idle(); +@@ -171,6 +171,16 @@ void arch_cpu_idle_dead(void) } + #endif +char bcm2708_reboot_mode = 'h'; + @@ -2028,10 +2028,10 @@ index 0000000..0aa916e +#endif diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c new file mode 100644 -index 0000000..2aa15f6 +index 0000000..752ae6e --- /dev/null +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -0,0 +1,717 @@ +@@ -0,0 +1,720 @@ +/* + * linux/arch/arm/mach-bcm2708/bcm2708.c + * @@ -2068,7 +2068,7 @@ index 0000000..2aa15f6 + +#include +#include -+#include ++#include +#include +#include +#include @@ -2606,9 +2606,12 @@ index 0000000..2aa15f6 + struct clock_event_device *unused) +{ + unsigned long stc; -+ -+ stc = readl(__io_address(ST_BASE + 0x04)); -+ writel(stc + cycles, __io_address(ST_BASE + 0x18)); /* stc3 */ ++ do { ++ stc = readl(__io_address(ST_BASE + 0x04)); ++ /* We could take a FIQ here, which may push ST above STC3 */ ++ writel(stc + cycles, __io_address(ST_BASE + 0x18)); ++ } while ((signed long) (readl(__io_address(ST_BASE + 0x04)) - stc) ++ >= (signed long) cycles); + return 0; +} + @@ -6523,7 +6526,7 @@ index 0000000..5e43e85 +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bcm-mbox"); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig -index ca8ecde..4afbeda 100644 +index 5bf7c3c..02c089e 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -358,7 +358,7 @@ config CPU_PJ4B @@ -6575,7 +6578,7 @@ index a10297d..c9ddd87 100644 ics_if_voip MACH_ICS_IF_VOIP ICS_IF_VOIP 3206 wlf_cragg_6410 MACH_WLF_CRAGG_6410 WLF_CRAGG_6410 3207 diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 1384f67..bad4c9b 100644 +index 8aaf8c1..f1cd961 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -272,6 +272,27 @@ config MMC_SDHCI_BCM_KONA @@ -6607,7 +6610,7 @@ index 1384f67..bad4c9b 100644 tristate "SDHCI platform support for the BCM2835 SD/MMC Controller" depends on ARCH_BCM2835 diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile -index 3483b6b..11460d7 100644 +index 0c8aa5e..a8614dd 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o @@ -8049,7 +8052,7 @@ index 0000000..d8ef77c +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRIVER_NAME); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index 9ddef47..b78afa2 100644 +index 9a79fc4..4be4fc8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -28,6 +28,7 @@ @@ -8272,7 +8275,7 @@ index 9ddef47..b78afa2 100644 + sdhci_readl(host, SDHCI_INT_STATUS)); timeout = jiffies; - if (!cmd->data && cmd->cmd_timeout_ms > 9000) + if (!cmd->data && cmd->busy_timeout > 9000) @@ -1026,6 +1036,10 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mod_timer(&host->timer, timeout); @@ -8293,7 +8296,7 @@ index 9ddef47..b78afa2 100644 u16 clk, ctrl_2; /* In case of UHS-I modes, set High Speed Enable */ -@@ -2204,7 +2218,7 @@ static void sdhci_timeout_timer(unsigned long data) +@@ -2203,7 +2217,7 @@ static void sdhci_timeout_timer(unsigned long data) if (host->mrq) { pr_err("%s: Timeout waiting for hardware " @@ -8302,7 +8305,7 @@ index 9ddef47..b78afa2 100644 sdhci_dumpregs(host); if (host->data) { -@@ -2249,10 +2263,13 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) +@@ -2248,10 +2262,13 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) BUG_ON(intmask == 0); if (!host->cmd) { @@ -8316,7 +8319,7 @@ index 9ddef47..b78afa2 100644 return; } -@@ -2322,6 +2339,19 @@ static void sdhci_show_adma_error(struct sdhci_host *host) +@@ -2321,6 +2338,19 @@ static void sdhci_show_adma_error(struct sdhci_host *host) static void sdhci_show_adma_error(struct sdhci_host *host) { } #endif @@ -8336,7 +8339,7 @@ index 9ddef47..b78afa2 100644 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { u32 command; -@@ -2351,23 +2381,39 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +@@ -2350,23 +2380,39 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } @@ -8380,7 +8383,7 @@ index 9ddef47..b78afa2 100644 pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); sdhci_show_adma_error(host); host->data->error = -EIO; -@@ -2375,11 +2421,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +@@ -2374,11 +2420,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) host->ops->adma_workaround(host, intmask); } @@ -8403,7 +8406,7 @@ index 9ddef47..b78afa2 100644 /* * We currently don't do anything fancy with DMA -@@ -2408,18 +2461,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +@@ -2407,18 +2460,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); } @@ -8424,7 +8427,7 @@ index 9ddef47..b78afa2 100644 } } -@@ -2475,6 +2518,22 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) +@@ -2472,6 +2515,22 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) tasklet_schedule(&host->card_tasklet); } @@ -8447,7 +8450,7 @@ index 9ddef47..b78afa2 100644 if (intmask & SDHCI_INT_CMD_MASK) { sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS); -@@ -2489,7 +2548,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) +@@ -2486,7 +2545,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); @@ -8462,7 +8465,7 @@ index 9ddef47..b78afa2 100644 if (intmask & SDHCI_INT_BUS_POWER) { pr_err("%s: Card is consuming too much power!\n", -@@ -2602,7 +2667,8 @@ int sdhci_resume_host(struct sdhci_host *host) +@@ -2599,7 +2664,8 @@ int sdhci_resume_host(struct sdhci_host *host) { int ret = 0; @@ -8472,7 +8475,7 @@ index 9ddef47..b78afa2 100644 if (host->ops->enable_dma) host->ops->enable_dma(host); } -@@ -2833,14 +2899,16 @@ int sdhci_add_host(struct sdhci_host *host) +@@ -2830,14 +2896,16 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_ADMA; } @@ -8491,7 +8494,7 @@ index 9ddef47..b78afa2 100644 } } } -@@ -3266,6 +3334,7 @@ int sdhci_add_host(struct sdhci_host *host) +@@ -3264,6 +3332,7 @@ int sdhci_add_host(struct sdhci_host *host) pr_info("%s: SDHCI controller on %s [%s] using %s\n", mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), @@ -8555,7 +8558,7 @@ index 0a3ed01..6857875 100644 extern int sdhci_runtime_suspend_host(struct sdhci_host *host); extern int sdhci_runtime_resume_host(struct sdhci_host *host); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index d58783d..4f7dbb2 100644 +index dacf0a0..3273cc2 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -84,7 +84,7 @@ struct vendor_data { @@ -8568,10 +8571,10 @@ index d58783d..4f7dbb2 100644 static struct vendor_data vendor_arm = { diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h -index 362927c4..e23fffb 100644 +index 7be12b8..a968bd6 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h -@@ -133,6 +133,7 @@ struct sdhci_host { +@@ -135,6 +135,7 @@ struct sdhci_host { #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ #define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */ #define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */ @@ -8579,7 +8582,7 @@ index 362927c4..e23fffb 100644 unsigned int version; /* SDHCI spec. version */ -@@ -148,6 +149,7 @@ struct sdhci_host { +@@ -150,6 +151,7 @@ struct sdhci_host { struct mmc_request *mrq; /* Current request */ struct mmc_command *cmd; /* Current command */ @@ -8591,10 +8594,10 @@ index 362927c4..e23fffb 100644 1.9.3 -From a75faf3c0fc55534dae87b6fe0476daef521857e Mon Sep 17 00:00:00 2001 +From ec5fb87c5db9a5bbbe6aaaa3b645ba3a3d3b87bb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 22:20:24 +0100 -Subject: [PATCH 002/124] Add quick config. +Subject: [PATCH 02/53] Add quick config. This is designed for quick compiling when developing. No modules are needed and it includes all Pi specific drivers @@ -8810,10 +8813,10 @@ index 0000000..e5efe75 1.9.3 -From 86d07672c0fb7b0855d513b6035f82e3ee0fdd5b Mon Sep 17 00:00:00 2001 +From 80008786c317729eecb00537c1a2a8ebc2e809a2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 003/124] Add dwc_otg driver +Subject: [PATCH 03/53] Add dwc_otg driver Signed-off-by: popcornmix --- @@ -8954,7 +8957,7 @@ index 1ae2bf3..c4a45aa 100644 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/ obj-$(CONFIG_USB_FUSBH200_HCD) += host/ diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c -index acbfeb0..7d675c8 100644 +index 358ca8d..abaac7c 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -152,6 +152,7 @@ int usb_choose_configuration(struct usb_device *udev) @@ -8966,10 +8969,10 @@ index acbfeb0..7d675c8 100644 return i; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c -index f829a1a..4a44ae7 100644 +index 0c8a7fc..e5dca4d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c -@@ -1888,6 +1888,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) +@@ -1891,6 +1891,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); @@ -12952,10 +12955,10 @@ index 0000000..a896d73 +} +module_exit(fsg_cleanup); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index a9707da..e252b95 100644 +index 3d9e540..e881817 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig -@@ -689,6 +689,19 @@ config USB_HWA_HCD +@@ -685,6 +685,19 @@ config USB_HWA_HCD To compile this driver a module, choose M here: the module will be called "hwa-hc". @@ -65885,24 +65888,24 @@ index 0000000..cdc9963 1.9.3 -From 32b0489eef241854097fa5ef29b2417aedea7ff8 Mon Sep 17 00:00:00 2001 +From db3ceff1eea2b9c0a96b67b86e4765d301b09875 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 004/124] bcm2708 watchdog driver +Subject: [PATCH 04/53] bcm2708 watchdog driver Signed-off-by: popcornmix --- drivers/watchdog/Kconfig | 6 + drivers/watchdog/Makefile | 1 + - drivers/watchdog/bcm2708_wdog.c | 384 ++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 391 insertions(+) + drivers/watchdog/bcm2708_wdog.c | 382 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 389 insertions(+) create mode 100644 drivers/watchdog/bcm2708_wdog.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index 79d2589..3641dbd 100644 +index 74ec8fc..dbe8bf8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig -@@ -402,6 +402,12 @@ config RETU_WATCHDOG +@@ -411,6 +411,12 @@ config RETU_WATCHDOG To compile this driver as a module, choose M here: the module will be called retu_wdt. @@ -65916,7 +65919,7 @@ index 79d2589..3641dbd 100644 tristate "MOXART watchdog" depends on ARCH_MOXART diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile -index 985a66c..f68e32c 100644 +index 1b5f3d5..f3730ed 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o @@ -65929,10 +65932,10 @@ index 985a66c..f68e32c 100644 obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o diff --git a/drivers/watchdog/bcm2708_wdog.c b/drivers/watchdog/bcm2708_wdog.c new file mode 100644 -index 0000000..2f19203 +index 0000000..8a27d68 --- /dev/null +++ b/drivers/watchdog/bcm2708_wdog.c -@@ -0,0 +1,384 @@ +@@ -0,0 +1,382 @@ +/* + * Broadcom BCM2708 watchdog driver. + * @@ -65961,8 +65964,6 @@ index 0000000..2f19203 +#include +#include + -+#include -+ +#define SECS_TO_WDOG_TICKS(x) ((x) << 16) +#define WDOG_TICKS_TO_SECS(x) ((x) >> 16) + @@ -66321,27 +66322,27 @@ index 0000000..2f19203 1.9.3 -From d83f89dffb2fadfb58f3335e43676681d67b5af2 Mon Sep 17 00:00:00 2001 +From de39ca1ccc039893df6cab59cf8872947c2b1e03 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:55:09 +0100 -Subject: [PATCH 005/124] bcm2708 framebuffer driver +Subject: [PATCH 05/53] bcm2708 framebuffer driver Signed-off-by: popcornmix --- - drivers/video/Kconfig | 14 + - drivers/video/Makefile | 1 + - drivers/video/bcm2708_fb.c | 499 ++++++ + drivers/video/fbdev/Kconfig | 14 + + drivers/video/fbdev/Makefile | 1 + + drivers/video/fbdev/bcm2708_fb.c | 499 ++++++ drivers/video/logo/logo_linux_clut224.ppm | 2483 ++++++++++------------------- 4 files changed, 1395 insertions(+), 1602 deletions(-) - create mode 100644 drivers/video/bcm2708_fb.c + create mode 100644 drivers/video/fbdev/bcm2708_fb.c -diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig -index dade5b7..4afc29b 100644 ---- a/drivers/video/Kconfig -+++ b/drivers/video/Kconfig -@@ -310,6 +310,20 @@ config FB_PM2_FIFO_DISCONNECT - help - Support the Permedia2 FIFO disconnect feature. +diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig +index e1f4727..541716e 100644 +--- a/drivers/video/fbdev/Kconfig ++++ b/drivers/video/fbdev/Kconfig +@@ -220,6 +220,20 @@ config FB_TILEBLITTING + comment "Frame buffer hardware drivers" + depends on FB +config FB_BCM2708 + tristate "BCM2708 framebuffer support" @@ -66357,26 +66358,26 @@ index dade5b7..4afc29b 100644 + here and read . The module + will be called bcm2708_fb. + - config FB_ARMCLCD - tristate "ARM PrimeCell PL110 support" - depends on ARM || ARM64 || COMPILE_TEST -diff --git a/drivers/video/Makefile b/drivers/video/Makefile -index ae17ddf..35654ba 100644 ---- a/drivers/video/Makefile -+++ b/drivers/video/Makefile -@@ -100,6 +100,7 @@ obj-$(CONFIG_FB_PVR2) += pvr2fb.o - obj-$(CONFIG_FB_VOODOO1) += sstfb.o - obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o - obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o + config FB_GRVGA + tristate "Aeroflex Gaisler framebuffer support" + depends on FB && SPARC +diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile +index 0284f2a..13c0664 100644 +--- a/drivers/video/fbdev/Makefile ++++ b/drivers/video/fbdev/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_FB_MACMODES) += macmodes.o + obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o + + # Hardware specific drivers go first +obj-$(CONFIG_FB_BCM2708) += bcm2708_fb.o - obj-$(CONFIG_FB_68328) += 68328fb.o - obj-$(CONFIG_FB_GBE) += gbefb.o - obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o -diff --git a/drivers/video/bcm2708_fb.c b/drivers/video/bcm2708_fb.c + obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o + obj-$(CONFIG_FB_ARC) += arcfb.o + obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o +diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c new file mode 100644 index 0000000..54cd760 --- /dev/null -+++ b/drivers/video/bcm2708_fb.c ++++ b/drivers/video/fbdev/bcm2708_fb.c @@ -0,0 +1,499 @@ +/* + * linux/drivers/video/bcm2708_fb.c @@ -69371,10 +69372,10 @@ index 3c14e43..7626beb 100644 1.9.3 -From b8e41e9f36d71217b268a1cc2c9e162601e5729b Mon Sep 17 00:00:00 2001 +From 9bb9779f379fd113719fd4c0fbb986a9894ced14 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 006/124] bcm2708 vchiq driver +Subject: [PATCH 06/53] bcm2708 vchiq driver Signed-off-by: popcornmix @@ -69457,7 +69458,7 @@ Signed-off-by: Daniel Stone create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 6cb388e..56867fa 100644 +index 8baff0e..0706e83 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -524,6 +524,7 @@ source "drivers/misc/carma/Kconfig" @@ -69467,18 +69468,19 @@ index 6cb388e..56867fa 100644 +source "drivers/misc/vc04_services/Kconfig" source "drivers/misc/mic/Kconfig" source "drivers/misc/genwqe/Kconfig" - endmenu + source "drivers/misc/echo/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index 99b9424..ad85616 100644 +index 7eb4b69..8f7c678 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -52,5 +52,6 @@ obj-$(CONFIG_INTEL_MEI) += mei/ +@@ -52,6 +52,7 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o +obj-y += vc04_services/ obj-y += mic/ obj-$(CONFIG_GENWQE) += genwqe/ + obj-$(CONFIG_ECHO) += echo/ diff --git a/drivers/misc/vc04_services/Kconfig b/drivers/misc/vc04_services/Kconfig new file mode 100644 index 0000000..2663933 @@ -81925,10 +81927,177 @@ index 0000000..b6bfa21 1.9.3 -From eb2dce617c1873f85fbd76aa1b4aea2f5c48cbc2 Mon Sep 17 00:00:00 2001 +From 857366f5cc92ec3ca752e1a1d5e670b4c81b7176 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 12 May 2014 15:12:02 +0100 +Subject: [PATCH 07/53] vchiq: Avoid high load when blocked and unkillable + +--- + .../interface/vchiq_arm/vchiq_2835_arm.c | 1 + + .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 1 + + .../interface/vchiq_arm/vchiq_connected.c | 1 + + .../vc04_services/interface/vchiq_arm/vchiq_core.c | 1 + + .../interface/vchiq_arm/vchiq_kern_lib.c | 1 + + .../interface/vchiq_arm/vchiq_killable.h | 69 ++++++++++++++++++++++ + .../vc04_services/interface/vchiq_arm/vchiq_util.c | 1 + + 7 files changed, 75 insertions(+) + create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +index b3bdaa2..7e7b09f 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +@@ -56,6 +56,7 @@ + #include "vchiq_arm.h" + #include "vchiq_2835.h" + #include "vchiq_connected.h" ++#include "vchiq_killable.h" + + #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2) + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c +index c1fb8c3..99c8967 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -49,6 +49,7 @@ + #include "vchiq_core.h" + #include "vchiq_ioctl.h" + #include "vchiq_arm.h" ++#include "vchiq_killable.h" + + #define DEVICE_NAME "vchiq" + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c +index 65f4b52..5efc62f 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c +@@ -33,6 +33,7 @@ + + #include "vchiq_connected.h" + #include "vchiq_core.h" ++#include "vchiq_killable.h" + #include + #include + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c +index f35ed4f..71ed0a5 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c +@@ -32,6 +32,7 @@ + */ + + #include "vchiq_core.h" ++#include "vchiq_killable.h" + + #define VCHIQ_SLOT_HANDLER_STACK 8192 + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c +index be9735f..5a4182e 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c +@@ -39,6 +39,7 @@ + + #include "vchiq_core.h" + #include "vchiq_arm.h" ++#include "vchiq_killable.h" + + /* ---- Public Variables ------------------------------------------------- */ + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h +new file mode 100644 +index 0000000..505ee1a +--- /dev/null ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h +@@ -0,0 +1,69 @@ ++/** ++ * Copyright (c) 2010-2012 Broadcom. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the above-listed copyright holders may not be used ++ * to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2, as published by the Free ++ * Software Foundation. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef VCHIQ_KILLABLE_H ++#define VCHIQ_KILLABLE_H ++ ++#include ++#include ++ ++#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT)) ++ ++static inline int __must_check down_interruptible_killable(struct semaphore *sem) ++{ ++ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */ ++ int ret; ++ sigset_t blocked, oldset; ++ siginitsetinv(&blocked, SHUTDOWN_SIGS); ++ sigprocmask(SIG_SETMASK, &blocked, &oldset); ++ ret = down_interruptible(sem); ++ sigprocmask(SIG_SETMASK, &oldset, NULL); ++ return ret; ++} ++#define down_interruptible down_interruptible_killable ++ ++ ++static inline int __must_check mutex_lock_interruptible_killable(struct mutex *lock) ++{ ++ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */ ++ int ret; ++ sigset_t blocked, oldset; ++ siginitsetinv(&blocked, SHUTDOWN_SIGS); ++ sigprocmask(SIG_SETMASK, &blocked, &oldset); ++ ret = mutex_lock_interruptible(lock); ++ sigprocmask(SIG_SETMASK, &oldset, NULL); ++ return ret; ++} ++#define mutex_lock_interruptible mutex_lock_interruptible_killable ++ ++#endif +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c +index c2eefef..05e7979 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c +@@ -32,6 +32,7 @@ + */ + + #include "vchiq_util.h" ++#include "vchiq_killable.h" + + static inline int is_pow2(int i) + { +-- +1.9.3 + + +From c402e40f29320bd699be82d1e14247e8e657beab Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 007/124] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 08/53] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix --- @@ -81948,7 +82117,7 @@ Signed-off-by: popcornmix create mode 100644 include/linux/broadcom/vc_cma.h diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index 1386749..fcf51a3 100644 +index 6e9f74a..17ff032 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -581,6 +581,8 @@ config DEVPORT @@ -83169,10 +83338,10 @@ index 0000000..a635f9f +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Broadcom Corporation"); diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index ad85616..8418ba7 100644 +index 8f7c678..524ab7d 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -52,6 +52,6 @@ obj-$(CONFIG_INTEL_MEI) += mei/ +@@ -52,7 +52,7 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o @@ -83180,6 +83349,7 @@ index ad85616..8418ba7 100644 +obj-$(CONFIG_BCM2708_VCHIQ) += vc04_services/ obj-y += mic/ obj-$(CONFIG_GENWQE) += genwqe/ + obj-$(CONFIG_ECHO) += echo/ diff --git a/include/linux/broadcom/vc_cma.h b/include/linux/broadcom/vc_cma.h new file mode 100644 index 0000000..5325832 @@ -83219,10 +83389,10 @@ index 0000000..5325832 1.9.3 -From 58ee732db2771b9b410a46eb84da0c20e1c402f4 Mon Sep 17 00:00:00 2001 +From e74ab01f67ba082f94066a5596fd22b20cd21b17 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 008/124] bcm2708: alsa sound driver +Subject: [PATCH 09/53] bcm2708: alsa sound driver Signed-off-by: popcornmix --- @@ -83308,7 +83478,7 @@ index 339aabf..df947e5 100644 CONFIG_USB_HIDDEV=y CONFIG_HID_A4TECH=m diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 2aa15f6..ac4c11d6 100644 +index 752ae6e..d60513f 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -431,6 +431,58 @@ struct platform_device bcm2708_powerman_device = { @@ -85586,13 +85756,12 @@ index 0000000..af3e6eb 1.9.3 -From 52a60c848945d3c50818ae14a15552bbad161e0f Mon Sep 17 00:00:00 2001 +From 2f7173137d8274100a9b040c6678c610f6cc47bb Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 26 Apr 2013 10:08:31 -0700 -Subject: [PATCH 009/124] Merge pull request #286 from - martinezjavier/rpi-3.6.y-dev +Subject: [PATCH 10/53] alsa: add mmap support and some cleanups to bcm2835 + ALSA driver -add mmap support and some cleanups to bcm2835 ALSA driver --- sound/arm/bcm2835-pcm.c | 69 ++++++++++++++++++++++-------------- sound/arm/bcm2835-vchiq.c | 89 +++++++++++++++++++++++++++++++++-------------- @@ -86070,10 +86239,10 @@ index 080bd5c..36afee3 100755 1.9.3 -From cd9f2edc896dc9f84d7854676a445234cb96498f Mon Sep 17 00:00:00 2001 +From d6a322aaf67b98d3dca2db19a17deaa3b241a7b9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 010/124] Add hwrng (hardware random number generator) driver +Subject: [PATCH 11/53] Add hwrng (hardware random number generator) driver --- arch/arm/mach-bcm2708/include/mach/platform.h | 1 + @@ -86096,7 +86265,7 @@ index 110ce07..ecd854e 100644 #define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */ #define MMCI0_BASE (BCM2708_PERI_BASE + 0x202000) /* MMC interface */ diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig -index 2f2b084..cfca8e9 100644 +index 244759b..7cebca0 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -341,6 +341,17 @@ config HW_RANDOM_TPM @@ -86115,8 +86284,8 @@ index 2f2b084..cfca8e9 100644 + If unsure, say N. + config HW_RANDOM_MSM - tristate "Qualcomm MSM Random Number Generator support" - depends on HW_RANDOM && ARCH_MSM + tristate "Qualcomm SoCs Random Number Generator support" + depends on HW_RANDOM && ARCH_QCOM diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 3ae7755..a7bfb80 100644 --- a/drivers/char/hw_random/Makefile @@ -86254,16 +86423,18 @@ index 0000000..1ffa7d7 1.9.3 -From a8d86bd11090bad4f1ab00113e4a38d3101cb9f7 Mon Sep 17 00:00:00 2001 +From 59bab50a0d0bf034729f91dab58fee0477c8eca3 Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 011/124] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 12/53] lirc: added support for RaspberryPi GPIO +lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others +See: https://github.com/raspberrypi/linux/issues/525 --- drivers/staging/media/lirc/Kconfig | 6 + drivers/staging/media/lirc/Makefile | 1 + - drivers/staging/media/lirc/lirc_rpi.c | 693 ++++++++++++++++++++++++++++++++++ - 3 files changed, 700 insertions(+) + drivers/staging/media/lirc/lirc_rpi.c | 695 ++++++++++++++++++++++++++++++++++ + 3 files changed, 702 insertions(+) create mode 100644 drivers/staging/media/lirc/lirc_rpi.c diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig @@ -86297,10 +86468,10 @@ index b90fcab..2b227fd 100644 obj-$(CONFIG_LIRC_SIR) += lirc_sir.o diff --git a/drivers/staging/media/lirc/lirc_rpi.c b/drivers/staging/media/lirc/lirc_rpi.c new file mode 100644 -index 0000000..8aee83f +index 0000000..57ffacf --- /dev/null +++ b/drivers/staging/media/lirc/lirc_rpi.c -@@ -0,0 +1,693 @@ +@@ -0,0 +1,695 @@ +/* + * lirc_rpi.c + * @@ -86333,6 +86504,7 @@ index 0000000..8aee83f +#include +#include +#include ++#include +#include +#include +#include @@ -86344,7 +86516,7 @@ index 0000000..8aee83f + +#define LIRC_DRIVER_NAME "lirc_rpi" +#define RBUF_LEN 256 -+#define LIRC_TRANSMITTER_LATENCY 256 ++#define LIRC_TRANSMITTER_LATENCY 50 + +#ifndef MAX_UDELAY_MS +#define MAX_UDELAY_US 5000 @@ -86410,19 +86582,15 @@ index 0000000..8aee83f +static int init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ -+ /* -+ * period, pulse/space width are kept with 8 binary places - -+ * IE multiplied by 256. -+ */ -+ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= ++ if (1000 * 1000000L / new_freq * new_duty_cycle / 100 <= + LIRC_TRANSMITTER_LATENCY) + return -EINVAL; -+ if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= ++ if (1000 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= + LIRC_TRANSMITTER_LATENCY) + return -EINVAL; + duty_cycle = new_duty_cycle; + freq = new_freq; -+ period = 256 * 1000000L / freq; ++ period = 1000 * 1000000L / freq; + pulse_width = period * duty_cycle / 100; + space_width = period - pulse_width; + dprintk("in init_timing_params, freq=%d pulse=%ld, " @@ -86433,11 +86601,14 @@ index 0000000..8aee83f +static long send_pulse_softcarrier(unsigned long length) +{ + int flag; -+ unsigned long actual, target, d; ++ unsigned long actual, target; ++ unsigned long actual_us, initial_us, target_us; + -+ length <<= 8; ++ length *= 1000; + + actual = 0; target = 0; flag = 0; ++ read_current_timer(&actual_us); ++ + while (actual < length) { + if (flag) { + gpiochip->set(gpiochip, gpio_out_pin, invert); @@ -86446,17 +86617,19 @@ index 0000000..8aee83f + gpiochip->set(gpiochip, gpio_out_pin, !invert); + target += pulse_width; + } -+ d = (target - actual - -+ LIRC_TRANSMITTER_LATENCY + 128) >> 8; ++ initial_us = actual_us; ++ target_us = actual_us + (target - actual) / 1000; + /* + * Note - we've checked in ioctl that the pulse/space + * widths are big enough so that d is > 0 + */ -+ udelay(d); -+ actual += (d << 8) + LIRC_TRANSMITTER_LATENCY; ++ if ((int)(target_us - actual_us) > 0) ++ udelay(target_us - actual_us); ++ read_current_timer(&actual_us); ++ actual += (actual_us - initial_us) * 1000; + flag = !flag; + } -+ return (actual-length) >> 8; ++ return (actual-length) / 1000; +} + +static long send_pulse(unsigned long length) @@ -86998,10 +87171,10 @@ index 0000000..8aee83f 1.9.3 -From 06565bccc8f03bd169a0b85654282e6865dfc3d9 Mon Sep 17 00:00:00 2001 +From 208e15e122803c08eaf86d1e4168e9168a7e899a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 8 May 2012 23:12:13 +0100 -Subject: [PATCH 012/124] Fixes for sdhci-bcm2708 +Subject: [PATCH 13/53] Fixes for sdhci-bcm2708 possible fix for sdcard missing status. Thank naren @@ -87114,10 +87287,10 @@ A typo also fixed in comments. 7 files changed, 365 insertions(+), 191 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c -index 7b5424f..687cccb 100644 +index 452782b..eee5aef 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c -@@ -1361,7 +1361,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, +@@ -1404,7 +1404,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, brq->data.blocks = 1; } @@ -87127,7 +87300,7 @@ index 7b5424f..687cccb 100644 * token, not a STOP_TRANSMISSION request. */ diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c -index 692fdb1..ea11f9c 100644 +index 2dd359d..f7753bf 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -15,6 +15,8 @@ @@ -87786,7 +87959,7 @@ index d8ef77c..3173c18 100644 + + diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index b78afa2..db67be8 100644 +index 4be4fc8..d6a6297 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -131,6 +131,99 @@ static void sdhci_dumpregs(struct sdhci_host *host) @@ -88038,7 +88211,7 @@ index b78afa2..db67be8 100644 } static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, -@@ -2101,7 +2199,7 @@ static void sdhci_card_event(struct mmc_host *mmc) +@@ -2100,7 +2198,7 @@ static void sdhci_card_event(struct mmc_host *mmc) if (host->ops->card_event) host->ops->card_event(host); @@ -88047,7 +88220,7 @@ index b78afa2..db67be8 100644 /* Check host->mrq first in case we are runtime suspended */ if (host->mrq && !sdhci_do_get_cd(host)) { -@@ -2117,7 +2215,7 @@ static void sdhci_card_event(struct mmc_host *mmc) +@@ -2116,7 +2214,7 @@ static void sdhci_card_event(struct mmc_host *mmc) tasklet_schedule(&host->finish_tasklet); } @@ -88056,7 +88229,7 @@ index b78afa2..db67be8 100644 } static const struct mmc_host_ops sdhci_ops = { -@@ -2156,14 +2254,14 @@ static void sdhci_tasklet_finish(unsigned long param) +@@ -2155,14 +2253,14 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; @@ -88073,7 +88246,7 @@ index b78afa2..db67be8 100644 return; } -@@ -2201,7 +2299,7 @@ static void sdhci_tasklet_finish(unsigned long param) +@@ -2200,7 +2298,7 @@ static void sdhci_tasklet_finish(unsigned long param) #endif mmiowb(); @@ -88082,7 +88255,7 @@ index b78afa2..db67be8 100644 mmc_request_done(host->mmc, mrq); sdhci_runtime_pm_put(host); -@@ -2214,7 +2312,7 @@ static void sdhci_timeout_timer(unsigned long data) +@@ -2213,7 +2311,7 @@ static void sdhci_timeout_timer(unsigned long data) host = (struct sdhci_host*)data; @@ -88091,7 +88264,7 @@ index b78afa2..db67be8 100644 if (host->mrq) { pr_err("%s: Timeout waiting for hardware " -@@ -2235,7 +2333,7 @@ static void sdhci_timeout_timer(unsigned long data) +@@ -2234,7 +2332,7 @@ static void sdhci_timeout_timer(unsigned long data) } mmiowb(); @@ -88100,7 +88273,7 @@ index b78afa2..db67be8 100644 } static void sdhci_tuning_timer(unsigned long data) -@@ -2245,11 +2343,11 @@ static void sdhci_tuning_timer(unsigned long data) +@@ -2244,11 +2342,11 @@ static void sdhci_tuning_timer(unsigned long data) host = (struct sdhci_host *)data; @@ -88114,7 +88287,7 @@ index b78afa2..db67be8 100644 } /*****************************************************************************\ -@@ -2473,10 +2571,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) +@@ -2472,10 +2570,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) u32 intmask, unexpected = 0; int cardint = 0, max_loops = 16; @@ -88124,10 +88297,10 @@ index b78afa2..db67be8 100644 if (host->runtime_suspended) { - spin_unlock(&host->lock); + sdhci_spin_unlock(host); - pr_warning("%s: got irq while runtime suspended\n", - mmc_hostname(host->mmc)); - return IRQ_HANDLED; -@@ -2588,7 +2686,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) + return IRQ_NONE; + } + +@@ -2585,7 +2683,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if (intmask && --max_loops) goto again; out: @@ -88136,7 +88309,7 @@ index b78afa2..db67be8 100644 if (unexpected) { pr_err("%s: Unexpected interrupt 0x%08x.\n", -@@ -2674,7 +2772,7 @@ int sdhci_resume_host(struct sdhci_host *host) +@@ -2671,7 +2769,7 @@ int sdhci_resume_host(struct sdhci_host *host) } if (!device_may_wakeup(mmc_dev(host->mmc))) { @@ -88145,7 +88318,7 @@ index b78afa2..db67be8 100644 mmc_hostname(host->mmc), host); if (ret) return ret; -@@ -2750,15 +2848,15 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) +@@ -2747,15 +2845,15 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) host->flags &= ~SDHCI_NEEDS_RETUNING; } @@ -88165,7 +88338,7 @@ index b78afa2..db67be8 100644 return ret; } -@@ -2784,16 +2882,16 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) +@@ -2781,16 +2879,16 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); if ((host_flags & SDHCI_PV_ENABLED) && !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { @@ -88185,7 +88358,7 @@ index b78afa2..db67be8 100644 host->runtime_suspended = false; -@@ -2804,7 +2902,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) +@@ -2801,7 +2899,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) /* Enable Card Detection */ sdhci_enable_card_detection(host); @@ -88194,7 +88367,7 @@ index b78afa2..db67be8 100644 return ret; } -@@ -3300,8 +3398,8 @@ int sdhci_add_host(struct sdhci_host *host) +@@ -3298,8 +3396,8 @@ int sdhci_add_host(struct sdhci_host *host) sdhci_init(host, 0); @@ -88205,7 +88378,7 @@ index b78afa2..db67be8 100644 if (ret) { pr_err("%s: Failed to request IRQ %d: %d\n", mmc_hostname(mmc), host->irq, ret); -@@ -3362,7 +3460,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) +@@ -3360,7 +3458,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) unsigned long flags; if (dead) { @@ -88214,7 +88387,7 @@ index b78afa2..db67be8 100644 host->flags |= SDHCI_DEVICE_DEAD; -@@ -3374,7 +3472,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) +@@ -3372,7 +3470,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_schedule(&host->finish_tasklet); } @@ -88248,23 +88421,23 @@ index 6857875..649f3cf 100644 + #endif /* __SDHCI_HW_H */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h -index 99f5709..cd6f996 100644 +index cb61ea4..27b1da6 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h -@@ -282,6 +282,7 @@ struct mmc_host { +@@ -278,6 +278,7 @@ struct mmc_host { + #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ MMC_CAP2_PACKED_WR) #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ - #define MMC_CAP2_SANITIZE (1 << 15) /* Support Sanitize */ +#define MMC_CAP2_FORCE_MULTIBLOCK (1 << 31) /* Always use multiblock transfers */ mmc_pm_flag_t pm_caps; /* supported pm features */ diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h -index e23fffb..b1b6537 100644 +index a968bd6..df54b9b 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h -@@ -102,6 +102,7 @@ struct sdhci_host { - #define SDHCI_QUIRK2_BROKEN_HS200 (1<<6) +@@ -104,6 +104,7 @@ struct sdhci_host { + #define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7) int irq; /* Device IRQ */ + int second_irq; /* Additional IRQ to disable/enable in low-latency mode */ @@ -88275,10 +88448,10 @@ index e23fffb..b1b6537 100644 1.9.3 -From 2c83467c365e6b54eeb4e3324b9b6bab15c4ed8c Mon Sep 17 00:00:00 2001 +From 9756a21a0528a2bb043bb7b890e87fde53dfea79 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 013/124] Add cpufreq driver +Subject: [PATCH 14/53] Add cpufreq driver --- arch/arm/Kconfig | 1 + @@ -88289,10 +88462,10 @@ Subject: [PATCH 013/124] Add cpufreq driver create mode 100755 drivers/cpufreq/bcm2835-cpufreq.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 3e91b1e..25e595c 100644 +index 0e8b8df..4b43550 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -388,6 +388,7 @@ config ARCH_BCM2708 +@@ -393,6 +393,7 @@ config ARCH_BCM2708 select NEED_MACH_GPIO_H select NEED_MACH_MEMORY_H select CLKDEV_LOOKUP @@ -88301,10 +88474,10 @@ index 3e91b1e..25e595c 100644 select ARM_ERRATA_411920 select MACH_BCM2708 diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm -index 3129749..d12c80d 100644 +index 5805035..59efbe6 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm -@@ -235,6 +235,14 @@ config ARM_SPEAR_CPUFREQ +@@ -240,6 +240,14 @@ config ARM_SPEAR_CPUFREQ help This adds the CPUFreq driver support for SPEAr SOCs. @@ -88320,7 +88493,7 @@ index 3129749..d12c80d 100644 bool "TEGRA CPUFreq support" depends on ARCH_TEGRA diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index 7494565..228317f 100644 +index 0dbb963..bd05f53 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o @@ -88580,10 +88753,10 @@ index 0000000..7bc55bd 1.9.3 -From d39182b41abc18be84339cfab6422a365e93d68f Mon Sep 17 00:00:00 2001 +From 1f4501eacf46c40733466d8fb7a4b0141c1f7ecc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 014/124] Added hwmon/thermal driver for reporting core +Subject: [PATCH 15/53] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian --- @@ -88599,7 +88772,7 @@ Subject: [PATCH 014/124] Added hwmon/thermal driver for reporting core create mode 100644 drivers/thermal/bcm2835-thermal.c diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index ac4c11d6..61457cc 100644 +index d60513f..f8820d4 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -483,6 +483,14 @@ static struct platform_device bcm2708_alsa_devices[] = { @@ -88628,12 +88801,12 @@ index ac4c11d6..61457cc 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 5ce43d8..193c496 100644 +index 4af0da9..ad7c30f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig -@@ -1556,6 +1556,16 @@ config SENSORS_MC13783_ADC - help - Support for the A/D converter on MC13783 and MC13892 PMIC. +@@ -1602,6 +1602,16 @@ config SENSORS_ULTRA45 + This driver provides support for the Ultra45 workstation environmental + sensors. +config SENSORS_BCM2835 + depends on THERMAL_BCM2835=n @@ -88649,10 +88822,10 @@ index 5ce43d8..193c496 100644 comment "ACPI drivers" diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index ec7cde0..a06e078 100644 +index c48f987..396feed 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile -@@ -142,6 +142,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o +@@ -146,6 +146,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o @@ -88886,7 +89059,7 @@ index 0000000..5bbed45 + +module_platform_driver(bcm2835_hwmon_driver); diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig -index 5f88d76..2f8c704 100644 +index 2d51912..37fbdaa 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -196,6 +196,12 @@ config INTEL_POWERCLAMP @@ -89108,10 +89281,10 @@ index 0000000..85fceb5 1.9.3 -From 60af5da1c050be3de06fe2094e3108acddfdb98d Mon Sep 17 00:00:00 2001 +From c8b39ce4f92fa3ba3b09d15879e72a6d8c1ed9a2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 015/124] Allow mac address to be set in smsc95xx +Subject: [PATCH 16/53] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -89205,11 +89378,19 @@ index 424db65e..fc1ef4e 100644 1.9.3 -From 9666df472a1539a11446c98e13f567a7380aa5aa Mon Sep 17 00:00:00 2001 +From c89f782e90fc5013849d45cb41054eeaaca1c56c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 4 Nov 2013 18:56:10 +0000 -Subject: [PATCH 016/124] Add Chris Boot's i2c and spi drivers. +Subject: [PATCH 17/53] Add Chris Boot's i2c and spi drivers. +i2c-bcm2708: fixed baudrate + +Fixed issue where the wrong CDIV value was set for baudrates below 3815 Hz (for 250MHz bus clock). +In that case the computed CDIV value was more than 0xffff. However the CDIV register width is only 16 bits. +This resulted in incorrect setting of CDIV and higher baudrate than intended. +Example: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0x1704 -> 42430Hz +After correction: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0xffff -> 3815Hz +The correct baudrate is shown in the log after the cdiv > 0xffff correction. --- arch/arm/configs/bcmrpi_cutdown_defconfig | 9 + arch/arm/configs/bcmrpi_defconfig | 6 + @@ -89218,11 +89399,11 @@ Subject: [PATCH 016/124] Add Chris Boot's i2c and spi drivers. arch/arm/mach-bcm2708/include/mach/platform.h | 3 + drivers/i2c/busses/Kconfig | 19 + drivers/i2c/busses/Makefile | 1 + - drivers/i2c/busses/i2c-bcm2708.c | 408 +++++++++++++++++ + drivers/i2c/busses/i2c-bcm2708.c | 419 +++++++++++++++++ drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/spi-bcm2708.c | 626 ++++++++++++++++++++++++++ - 11 files changed, 1190 insertions(+), 2 deletions(-) + 11 files changed, 1201 insertions(+), 2 deletions(-) create mode 100644 drivers/i2c/busses/i2c-bcm2708.c create mode 100644 drivers/spi/spi-bcm2708.c @@ -89277,7 +89458,7 @@ index 9355841..e151ed4 100644 + Binds spidev driver to the SPI0 master endmenu diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 61457cc..624415b 100644 +index f8820d4..62c6280 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -31,6 +31,7 @@ @@ -89451,7 +89632,7 @@ index ecd854e..f4bb733 100644 #define MCORE_BASE (BCM2708_PERI_BASE + 0x0000) /* Fake frame buffer device (actually the multicore sync block*/ diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig -index c5eec02..315421d 100644 +index c94db1c..09c620f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -348,6 +348,25 @@ config I2C_BCM2835 @@ -89481,7 +89662,7 @@ index c5eec02..315421d 100644 tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile -index a08931f..a62fadf 100644 +index 18d18ff..7b9435a 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o @@ -89490,14 +89671,14 @@ index a08931f..a62fadf 100644 obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM2708) += i2c-bcm2708.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o + obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o - obj-$(CONFIG_I2C_CPM) += i2c-cpm.o diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c new file mode 100644 -index 0000000..98bc4e7 +index 0000000..f266f10 --- /dev/null +++ b/drivers/i2c/busses/i2c-bcm2708.c -@@ -0,0 +1,408 @@ +@@ -0,0 +1,419 @@ +/* + * Driver for Broadcom BCM2708 BSC Controllers + * @@ -89603,7 +89784,7 @@ index 0000000..98bc4e7 +#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) + + int pin; -+ u32 *gpio = ioremap(0x20200000, SZ_16K); ++ u32 *gpio = ioremap(GPIO_BASE, SZ_16K); + + BUG_ON(id != 0 && id != 1); + /* BSC0 is on GPIO 0 & 1, BSC1 is on GPIO 2 & 3 */ @@ -89655,6 +89836,8 @@ index 0000000..98bc4e7 + + bus_hz = clk_get_rate(bi->clk); + cdiv = bus_hz / baudrate; ++ if (cdiv > 0xffff) ++ cdiv = 0xffff; + + if (bi->msg->flags & I2C_M_RD) + c |= BSC_C_INTR | BSC_C_READ; @@ -89768,6 +89951,8 @@ index 0000000..98bc4e7 + struct clk *clk; + struct bcm2708_i2c *bi; + struct i2c_adapter *adap; ++ unsigned long bus_hz; ++ u32 cdiv; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { @@ -89843,8 +90028,15 @@ index 0000000..98bc4e7 + goto out_free_irq; + } + -+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %dk)\n", -+ pdev->id, (unsigned long)regs->start, irq, baudrate/1000); ++ bus_hz = clk_get_rate(bi->clk); ++ cdiv = bus_hz / baudrate; ++ if (cdiv > 0xffff) { ++ cdiv = 0xffff; ++ baudrate = bus_hz / cdiv; ++ } ++ ++ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", ++ pdev->id, (unsigned long)regs->start, irq, baudrate); + + return 0; + @@ -89907,7 +90099,7 @@ index 0000000..98bc4e7 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig -index 581ee2a..6029f6f 100644 +index 60f2b41..6015c1e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -85,6 +85,14 @@ config SPI_BCM2835 @@ -89926,7 +90118,7 @@ index 581ee2a..6029f6f 100644 tristate "SPI controller driver for ADI Blackfin5xx" depends on BLACKFIN && !BF60x diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile -index 95af48d..51996c2 100644 +index bd79266..81b30d1 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o @@ -89939,7 +90131,7 @@ index 95af48d..51996c2 100644 obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o diff --git a/drivers/spi/spi-bcm2708.c b/drivers/spi/spi-bcm2708.c new file mode 100644 -index 0000000..180264a +index 0000000..06dd02f --- /dev/null +++ b/drivers/spi/spi-bcm2708.c @@ -0,0 +1,626 @@ @@ -90053,7 +90245,7 @@ index 0000000..180264a +#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) + + int pin; -+ u32 *gpio = ioremap(0x20200000, SZ_16K); ++ u32 *gpio = ioremap(GPIO_BASE, SZ_16K); + + /* SPI is on GPIO 7..11 */ + for (pin = 7; pin <= 11; pin++) { @@ -90573,10 +90765,88 @@ index 0000000..180264a 1.9.3 -From 8a47aa1542b8d1af6c50859663d1d557c04d300a Mon Sep 17 00:00:00 2001 +From 387c7a0d0e903504c3393216c9cd29035af37272 Mon Sep 17 00:00:00 2001 +From: cbeytas +Date: Mon, 24 Jun 2013 00:05:40 -0400 +Subject: [PATCH 18/53] Perform I2C combined transactions when possible + +Perform I2C combined transactions whenever possible, within the +restrictions of the Broadcomm Serial Controller. + +Disable DONE interrupt during TA poll + +Prevent interrupt from being triggered if poll is missed and transfer +starts and finishes. + +i2c: Make combined transactions optional and disabled by default +--- + drivers/i2c/busses/i2c-bcm2708.c | 31 ++++++++++++++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c +index f266f10..8750634 100644 +--- a/drivers/i2c/busses/i2c-bcm2708.c ++++ b/drivers/i2c/busses/i2c-bcm2708.c +@@ -74,6 +74,9 @@ static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE; + module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + MODULE_PARM_DESC(baudrate, "The I2C baudrate"); + ++static bool combined = false; ++module_param(combined, bool, 0644); ++MODULE_PARM_DESC(combined, "Use combined transactions"); + + struct bcm2708_i2c { + struct i2c_adapter adapter; +@@ -150,7 +153,7 @@ static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi) + static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi) + { + unsigned long bus_hz; +- u32 cdiv; ++ u32 cdiv, s; + u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1; + + bus_hz = clk_get_rate(bi->clk); +@@ -166,6 +169,32 @@ static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi) + bcm2708_wr(bi, BSC_DIV, cdiv); + bcm2708_wr(bi, BSC_A, bi->msg->addr); + bcm2708_wr(bi, BSC_DLEN, bi->msg->len); ++ if (combined) ++ { ++ /* Do the next two messages meet combined transaction criteria? ++ - Current message is a write, next message is a read ++ - Both messages to same slave address ++ - Write message can fit inside FIFO (16 bytes or less) */ ++ if ( (bi->nmsgs > 1) && ++ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) && ++ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) { ++ /* Fill FIFO with entire write message (16 byte FIFO) */ ++ while (bi->pos < bi->msg->len) ++ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]); ++ /* Start write transfer (no interrupts, don't clear FIFO) */ ++ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST); ++ /* poll for transfer start bit (should only take 1-20 polls) */ ++ do { ++ s = bcm2708_rd(bi, BSC_S); ++ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE))); ++ /* Send next read message before the write transfer finishes. */ ++ bi->nmsgs--; ++ bi->msg++; ++ bi->pos = 0; ++ bcm2708_wr(bi, BSC_DLEN, bi->msg->len); ++ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ; ++ } ++ } + bcm2708_wr(bi, BSC_C, c); + } + +-- +1.9.3 + + +From 37afb4bff4b8b31eddfa28cfd49a6bd45dacf723 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 017/124] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 19/53] enabling the realtime clock 1-wire chip DS1307 and 1-wire on GPIO4 (as a module) 1-wire: Add support for configuring pin for w1-gpio kernel module @@ -90585,16 +90855,24 @@ See: https://github.com/raspberrypi/linux/pull/457 Add bitbanging pullups, use them for w1-gpio Allows parasite power to work, uses module option pullup=1 + +bcm2708: Ensure 1-wire pullup is disabled by default, and expose as module parameter + +Signed-off-by: Alex J Lennon + +w1-gpio: Add gpiopin module parameter and correctly free up gpio pull-up pin, if set + +Signed-off-by: Alex J Lennon --- - arch/arm/mach-bcm2708/bcm2708.c | 23 +++++++++++++++++++++++ - drivers/w1/masters/w1-gpio.c | 20 ++++++++++++++++++++ - drivers/w1/w1.h | 6 ++++++ - drivers/w1/w1_int.c | 14 ++++++++++++++ - drivers/w1/w1_io.c | 18 +++++++++++++++--- - 5 files changed, 78 insertions(+), 3 deletions(-) + arch/arm/mach-bcm2708/bcm2708.c | 29 ++++++++++++++++++++++ + drivers/w1/masters/w1-gpio.c | 55 +++++++++++++++++++++++++++++++++++++---- + drivers/w1/w1.h | 6 +++++ + drivers/w1/w1_int.c | 14 +++++++++++ + drivers/w1/w1_io.c | 18 +++++++++++--- + 5 files changed, 114 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 624415b..d315c19 100644 +index 62c6280..c8763c9 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -32,6 +32,7 @@ @@ -90605,12 +90883,14 @@ index 624415b..d315c19 100644 #include #include -@@ -76,12 +77,16 @@ +@@ -76,12 +77,19 @@ */ #define DMA_MASK_BITS_COMMON 32 +// use GPIO 4 for the one-wire GPIO pin, if enabled +#define W1_GPIO 4 ++// ensure one-wire GPIO pullup is disabled by default ++#define W1_PULLUP -1 + /* command line parameters */ static unsigned boardrev, serial; @@ -90619,16 +90899,18 @@ index 624415b..d315c19 100644 static unsigned disk_led_active_low = 1; static unsigned reboot_part = 0; +static unsigned w1_gpio_pin = W1_GPIO; ++static unsigned w1_gpio_pullup = W1_PULLUP; static void __init bcm2708_init_led(void); -@@ -258,6 +263,19 @@ static struct platform_device bcm2708_dmaman_device = { +@@ -258,6 +266,20 @@ static struct platform_device bcm2708_dmaman_device = { .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), }; +#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) +static struct w1_gpio_platform_data w1_gpio_pdata = { + .pin = W1_GPIO, ++ .ext_pullup_enable_pin = W1_PULLUP, + .is_open_drain = 0, +}; + @@ -90642,37 +90924,45 @@ index 624415b..d315c19 100644 static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); static struct platform_device bcm2708_fb_device = { -@@ -680,6 +698,10 @@ void __init bcm2708_init(void) +@@ -680,6 +702,11 @@ void __init bcm2708_init(void) #ifdef CONFIG_BCM2708_GPIO bcm_register_device(&bcm2708_gpio_device); #endif +#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) + w1_gpio_pdata.pin = w1_gpio_pin; ++ w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup; + platform_device_register(&w1_device); +#endif bcm_register_device(&bcm2708_systemtimer_device); bcm_register_device(&bcm2708_fb_device); bcm_register_device(&bcm2708_usb_device); -@@ -880,3 +902,4 @@ module_param(uart_clock, uint, 0644); +@@ -883,3 +910,5 @@ module_param(uart_clock, uint, 0644); module_param(disk_led_gpio, uint, 0644); module_param(disk_led_active_low, uint, 0644); module_param(reboot_part, uint, 0644); +module_param(w1_gpio_pin, uint, 0644); ++module_param(w1_gpio_pullup, uint, 0644); diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c -index 9709b8b..f8b769a 100644 +index 1d111e5..61be2cd 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c -@@ -23,6 +23,9 @@ +@@ -23,6 +23,15 @@ #include "../w1.h" #include "../w1_int.h" -+static int w1_gpio_pullup = 0; ++static int w1_gpio_pullup = -1; ++static int w1_gpio_pullup_orig = -1; +module_param_named(pullup, w1_gpio_pullup, int, 0); ++MODULE_PARM_DESC(pullup, "GPIO pin pullup number"); ++static int w1_gpio_pin = -1; ++static int w1_gpio_pin_orig = -1; ++module_param_named(gpiopin, w1_gpio_pin, int, 0); ++MODULE_PARM_DESC(gpiopin, "GPIO pin number"); + static u8 w1_gpio_set_pullup(void *data, int delay) { struct w1_gpio_platform_data *pdata = data; -@@ -67,6 +70,16 @@ static u8 w1_gpio_read_bit(void *data) +@@ -67,6 +76,16 @@ static u8 w1_gpio_read_bit(void *data) return gpio_get_value(pdata->pin) ? 1 : 0; } @@ -90689,26 +90979,78 @@ index 9709b8b..f8b769a 100644 #if defined(CONFIG_OF) static struct of_device_id w1_gpio_dt_ids[] = { { .compatible = "w1-gpio" }, -@@ -156,6 +169,13 @@ static int w1_gpio_probe(struct platform_device *pdev) +@@ -113,13 +132,15 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) + static int w1_gpio_probe(struct platform_device *pdev) + { + struct w1_bus_master *master; +- struct w1_gpio_platform_data *pdata; ++ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + int err; + +- if (of_have_populated_dt()) { +- err = w1_gpio_probe_dt(pdev); +- if (err < 0) +- return err; ++ if(pdata == NULL) { ++ if (of_have_populated_dt()) { ++ err = w1_gpio_probe_dt(pdev); ++ if (err < 0) ++ return err; ++ } + } + + pdata = dev_get_platdata(&pdev->dev); +@@ -136,6 +157,19 @@ static int w1_gpio_probe(struct platform_device *pdev) + return -ENOMEM; + } + ++ w1_gpio_pin_orig = pdata->pin; ++ w1_gpio_pullup_orig = pdata->ext_pullup_enable_pin; ++ ++ if(gpio_is_valid(w1_gpio_pin)) { ++ pdata->pin = w1_gpio_pin; ++ pdata->ext_pullup_enable_pin = -1; ++ } ++ if(gpio_is_valid(w1_gpio_pullup)) { ++ pdata->ext_pullup_enable_pin = w1_gpio_pullup; ++ } ++ ++ dev_info(&pdev->dev, "gpio pin %d, gpio pullup pin %d\n", pdata->pin, pdata->ext_pullup_enable_pin); ++ + err = devm_gpio_request(&pdev->dev, pdata->pin, "w1"); + if (err) { + dev_err(&pdev->dev, "gpio_request (pin) failed\n"); +@@ -165,6 +199,14 @@ static int w1_gpio_probe(struct platform_device *pdev) master->set_pullup = w1_gpio_set_pullup; } -+ if (w1_gpio_pullup) ++ if (gpio_is_valid(w1_gpio_pullup)) { + if (pdata->is_open_drain) + printk(KERN_ERR "w1-gpio 'pullup' option " + "doesn't work with open drain GPIO\n"); + else + master->bitbang_pullup = w1_gpio_bitbang_pullup; ++ } + err = w1_add_master_device(master); if (err) { dev_err(&pdev->dev, "w1_add_master device failed\n"); +@@ -195,6 +237,9 @@ static int w1_gpio_remove(struct platform_device *pdev) + + w1_remove_master_device(master); + ++ pdata->pin = w1_gpio_pin_orig; ++ pdata->ext_pullup_enable_pin = w1_gpio_pullup_orig; ++ + return 0; + } + diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h -index ca8081a..3392959 100644 +index 734dab7..a3a64d8 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h -@@ -148,6 +148,12 @@ struct w1_bus_master - */ +@@ -171,6 +171,12 @@ struct w1_bus_master + u8 (*set_pullup)(void *, int); + /** @@ -90717,14 +91059,14 @@ index ca8081a..3392959 100644 + */ + void (*bitbang_pullup) (void *, u8); + - /** Really nice hardware can handles the different types of ROM search - * w1_master* is passed to the slave found callback. - */ + void (*search)(void *, struct w1_master *, + u8, w1_slave_found_callback); + }; diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c -index 590bd8a..a4d69b6 100644 +index 9b084db..5c20492 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c -@@ -118,6 +118,20 @@ int w1_add_master_device(struct w1_bus_master *master) +@@ -124,6 +124,20 @@ int w1_add_master_device(struct w1_bus_master *master) return(-EINVAL); } @@ -90746,10 +91088,10 @@ index 590bd8a..a4d69b6 100644 mutex_lock(&w1_mlock); /* Search for the first available id (starting at 1). */ diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c -index e10acc2..667fdd5 100644 +index 2820924..fd0550f 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c -@@ -127,10 +127,22 @@ static void w1_pre_write(struct w1_master *dev) +@@ -134,10 +134,22 @@ static void w1_pre_write(struct w1_master *dev) static void w1_post_write(struct w1_master *dev) { if (dev->pullup_duration) { @@ -90779,1286 +91121,17 @@ index e10acc2..667fdd5 100644 1.9.3 -From 751f7b0d4ae59d62adca51253618608f7042f399 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 3 Jul 2013 00:46:42 +0100 -Subject: [PATCH 018/124] Add FIQ patch to dwc_otg driver. Enable with - dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance. Thanks - to Gordon and Costas - ---- - arch/arm/Kconfig | 1 + - arch/arm/include/asm/fiq.h | 1 + - arch/arm/kernel/fiq.c | 1 + - arch/arm/kernel/fiqasm.S | 7 ++ - arch/arm/mach-bcm2708/armctrl.c | 19 +++- - arch/arm/mach-bcm2708/bcm2708.c | 29 ++++- - arch/arm/mach-bcm2708/include/mach/irqs.h | 155 +++++++++++++------------- - arch/arm/mach-bcm2708/include/mach/platform.h | 2 + - drivers/usb/host/dwc_otg/Makefile | 1 + - drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 14 ++- - drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 1 + - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 37 +++++- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 5 + - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 2 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 5 + - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 154 ++++++++++++++++++++++--- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 45 ++++++++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 20 +++- - drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c | 113 +++++++++++++++++++ - drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h | 36 ++++++ - drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 3 + - 21 files changed, 543 insertions(+), 108 deletions(-) - create mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c - create mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h - -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 25e595c..4e56830 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -393,6 +393,7 @@ config ARCH_BCM2708 - select ARM_ERRATA_411920 - select MACH_BCM2708 - select VC4 -+ select FIQ - help - This enables support for Broadcom BCM2708 boards. - -diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h -index d493d0b..f1a131b 100644 ---- a/arch/arm/include/asm/fiq.h -+++ b/arch/arm/include/asm/fiq.h -@@ -42,6 +42,7 @@ extern void disable_fiq(int fiq); - /* helpers defined in fiqasm.S: */ - extern void __set_fiq_regs(unsigned long const *regs); - extern void __get_fiq_regs(unsigned long *regs); -+extern void __FIQ_Branch(unsigned long *regs); - - static inline void set_fiq_regs(struct pt_regs const *regs) - { -diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c -index 918875d..aac11f8 100644 ---- a/arch/arm/kernel/fiq.c -+++ b/arch/arm/kernel/fiq.c -@@ -142,6 +142,7 @@ void disable_fiq(int fiq) - EXPORT_SYMBOL(set_fiq_handler); - EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */ - EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */ -+EXPORT_SYMBOL(__FIQ_Branch); /* defined in fiqasm.S */ - EXPORT_SYMBOL(claim_fiq); - EXPORT_SYMBOL(release_fiq); - EXPORT_SYMBOL(enable_fiq); -diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S -index 207f9d6..93eddfe 100644 ---- a/arch/arm/kernel/fiqasm.S -+++ b/arch/arm/kernel/fiqasm.S -@@ -25,6 +25,9 @@ - ENTRY(__set_fiq_regs) - mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE - mrs r1, cpsr -+@@@@@@@@@@@@@@@ hack: enable the fiq here to keep usb driver happy -+ and r1, #~PSR_F_BIT -+@@@@@@@@@@@@@@@ endhack: (need to find better place for this to happen) - msr cpsr_c, r2 @ select FIQ mode - mov r0, r0 @ avoid hazard prior to ARMv4 - ldmia r0!, {r8 - r12} -@@ -47,3 +50,7 @@ ENTRY(__get_fiq_regs) - mov r0, r0 @ avoid hazard prior to ARMv4 - mov pc, lr - ENDPROC(__get_fiq_regs) -+ -+ENTRY(__FIQ_Branch) -+ mov pc, r8 -+ENDPROC(__FIQ_Branch) -diff --git a/arch/arm/mach-bcm2708/armctrl.c b/arch/arm/mach-bcm2708/armctrl.c -index da18725..274aa30 100644 ---- a/arch/arm/mach-bcm2708/armctrl.c -+++ b/arch/arm/mach-bcm2708/armctrl.c -@@ -52,8 +52,12 @@ static void armctrl_mask_irq(struct irq_data *d) - 0 - }; - -- unsigned int data = (unsigned int)irq_get_chip_data(d->irq); -- writel(1 << (data & 0x1f), __io_address(disables[(data >> 5) & 0x3])); -+ if (d->irq >= FIQ_START) { -+ writel(0, __io_address(ARM_IRQ_FAST)); -+ } else { -+ unsigned int data = (unsigned int)irq_get_chip_data(d->irq); -+ writel(1 << (data & 0x1f), __io_address(disables[(data >> 5) & 0x3])); -+ } - } - - static void armctrl_unmask_irq(struct irq_data *d) -@@ -65,8 +69,14 @@ static void armctrl_unmask_irq(struct irq_data *d) - 0 - }; - -- unsigned int data = (unsigned int)irq_get_chip_data(d->irq); -- writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3])); -+ if (d->irq >= FIQ_START) { -+ unsigned int data = -+ (unsigned int)irq_get_chip_data(d->irq) - FIQ_START; -+ writel(0x80 | data, __io_address(ARM_IRQ_FAST)); -+ } else { -+ unsigned int data = (unsigned int)irq_get_chip_data(d->irq); -+ writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3])); -+ } - } - - #if defined(CONFIG_PM) -@@ -204,5 +214,6 @@ int __init armctrl_init(void __iomem * base, unsigned int irq_start, - } - - armctrl_pm_register(base, irq_start, resume_sources); -+ init_FIQ(FIQ_START); - return 0; - } -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index d315c19..2b11e9d 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -317,12 +317,32 @@ static struct resource bcm2708_usb_resources[] = { - .flags = IORESOURCE_MEM, - }, - [1] = { -- .start = IRQ_USB, -- .end = IRQ_USB, -+ .start = MPHI_BASE, -+ .end = MPHI_BASE + SZ_4K - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [2] = { -+ .start = IRQ_HOSTPORT, -+ .end = IRQ_HOSTPORT, - .flags = IORESOURCE_IRQ, - }, - }; - -+bool fiq_fix_enable = true; -+ -+static struct resource bcm2708_usb_resources_no_fiq_fix[] = { -+ [0] = { -+ .start = USB_BASE, -+ .end = USB_BASE + SZ_128K - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_USB, -+ .end = IRQ_USB, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ - static u64 usb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); - - static struct platform_device bcm2708_usb_device = { -@@ -704,6 +724,11 @@ void __init bcm2708_init(void) - #endif - bcm_register_device(&bcm2708_systemtimer_device); - bcm_register_device(&bcm2708_fb_device); -+ if (!fiq_fix_enable) -+ { -+ bcm2708_usb_device.resource = bcm2708_usb_resources_no_fiq_fix; -+ bcm2708_usb_device.num_resources = ARRAY_SIZE(bcm2708_usb_resources_no_fiq_fix); -+ } - bcm_register_device(&bcm2708_usb_device); - bcm_register_device(&bcm2708_uart1_device); - bcm_register_device(&bcm2708_powerman_device); -diff --git a/arch/arm/mach-bcm2708/include/mach/irqs.h b/arch/arm/mach-bcm2708/include/mach/irqs.h -index faf5d1a..4299054 100644 ---- a/arch/arm/mach-bcm2708/include/mach/irqs.h -+++ b/arch/arm/mach-bcm2708/include/mach/irqs.h -@@ -106,89 +106,92 @@ - #define IRQ_PENDING1 (IRQ_ARMCTRL_START + INTERRUPT_PENDING1) - #define IRQ_PENDING2 (IRQ_ARMCTRL_START + INTERRUPT_PENDING2) - -+#define FIQ_START HARD_IRQS -+ - /* - * FIQ interrupts definitions are the same as the INT definitions. - */ --#define FIQ_TIMER0 INT_TIMER0 --#define FIQ_TIMER1 INT_TIMER1 --#define FIQ_TIMER2 INT_TIMER2 --#define FIQ_TIMER3 INT_TIMER3 --#define FIQ_CODEC0 INT_CODEC0 --#define FIQ_CODEC1 INT_CODEC1 --#define FIQ_CODEC2 INT_CODEC2 --#define FIQ_JPEG INT_JPEG --#define FIQ_ISP INT_ISP --#define FIQ_USB INT_USB --#define FIQ_3D INT_3D --#define FIQ_TRANSPOSER INT_TRANSPOSER --#define FIQ_MULTICORESYNC0 INT_MULTICORESYNC0 --#define FIQ_MULTICORESYNC1 INT_MULTICORESYNC1 --#define FIQ_MULTICORESYNC2 INT_MULTICORESYNC2 --#define FIQ_MULTICORESYNC3 INT_MULTICORESYNC3 --#define FIQ_DMA0 INT_DMA0 --#define FIQ_DMA1 INT_DMA1 --#define FIQ_DMA2 INT_DMA2 --#define FIQ_DMA3 INT_DMA3 --#define FIQ_DMA4 INT_DMA4 --#define FIQ_DMA5 INT_DMA5 --#define FIQ_DMA6 INT_DMA6 --#define FIQ_DMA7 INT_DMA7 --#define FIQ_DMA8 INT_DMA8 --#define FIQ_DMA9 INT_DMA9 --#define FIQ_DMA10 INT_DMA10 --#define FIQ_DMA11 INT_DMA11 --#define FIQ_DMA12 INT_DMA12 --#define FIQ_AUX INT_AUX --#define FIQ_ARM INT_ARM --#define FIQ_VPUDMA INT_VPUDMA --#define FIQ_HOSTPORT INT_HOSTPORT --#define FIQ_VIDEOSCALER INT_VIDEOSCALER --#define FIQ_CCP2TX INT_CCP2TX --#define FIQ_SDC INT_SDC --#define FIQ_DSI0 INT_DSI0 --#define FIQ_AVE INT_AVE --#define FIQ_CAM0 INT_CAM0 --#define FIQ_CAM1 INT_CAM1 --#define FIQ_HDMI0 INT_HDMI0 --#define FIQ_HDMI1 INT_HDMI1 --#define FIQ_PIXELVALVE1 INT_PIXELVALVE1 --#define FIQ_I2CSPISLV INT_I2CSPISLV --#define FIQ_DSI1 INT_DSI1 --#define FIQ_PWA0 INT_PWA0 --#define FIQ_PWA1 INT_PWA1 --#define FIQ_CPR INT_CPR --#define FIQ_SMI INT_SMI --#define FIQ_GPIO0 INT_GPIO0 --#define FIQ_GPIO1 INT_GPIO1 --#define FIQ_GPIO2 INT_GPIO2 --#define FIQ_GPIO3 INT_GPIO3 --#define FIQ_I2C INT_I2C --#define FIQ_SPI INT_SPI --#define FIQ_I2SPCM INT_I2SPCM --#define FIQ_SDIO INT_SDIO --#define FIQ_UART INT_UART --#define FIQ_SLIMBUS INT_SLIMBUS --#define FIQ_VEC INT_VEC --#define FIQ_CPG INT_CPG --#define FIQ_RNG INT_RNG --#define FIQ_ARASANSDIO INT_ARASANSDIO --#define FIQ_AVSPMON INT_AVSPMON -+#define FIQ_TIMER0 (FIQ_START+INTERRUPT_TIMER0) -+#define FIQ_TIMER1 (FIQ_START+INTERRUPT_TIMER1) -+#define FIQ_TIMER2 (FIQ_START+INTERRUPT_TIMER2) -+#define FIQ_TIMER3 (FIQ_START+INTERRUPT_TIMER3) -+#define FIQ_CODEC0 (FIQ_START+INTERRUPT_CODEC0) -+#define FIQ_CODEC1 (FIQ_START+INTERRUPT_CODEC1) -+#define FIQ_CODEC2 (FIQ_START+INTERRUPT_CODEC2) -+#define FIQ_JPEG (FIQ_START+INTERRUPT_JPEG) -+#define FIQ_ISP (FIQ_START+INTERRUPT_ISP) -+#define FIQ_USB (FIQ_START+INTERRUPT_USB) -+#define FIQ_3D (FIQ_START+INTERRUPT_3D) -+#define FIQ_TRANSPOSER (FIQ_START+INTERRUPT_TRANSPOSER) -+#define FIQ_MULTICORESYNC0 (FIQ_START+INTERRUPT_MULTICORESYNC0) -+#define FIQ_MULTICORESYNC1 (FIQ_START+INTERRUPT_MULTICORESYNC1) -+#define FIQ_MULTICORESYNC2 (FIQ_START+INTERRUPT_MULTICORESYNC2) -+#define FIQ_MULTICORESYNC3 (FIQ_START+INTERRUPT_MULTICORESYNC3) -+#define FIQ_DMA0 (FIQ_START+INTERRUPT_DMA0) -+#define FIQ_DMA1 (FIQ_START+INTERRUPT_DMA1) -+#define FIQ_DMA2 (FIQ_START+INTERRUPT_DMA2) -+#define FIQ_DMA3 (FIQ_START+INTERRUPT_DMA3) -+#define FIQ_DMA4 (FIQ_START+INTERRUPT_DMA4) -+#define FIQ_DMA5 (FIQ_START+INTERRUPT_DMA5) -+#define FIQ_DMA6 (FIQ_START+INTERRUPT_DMA6) -+#define FIQ_DMA7 (FIQ_START+INTERRUPT_DMA7) -+#define FIQ_DMA8 (FIQ_START+INTERRUPT_DMA8) -+#define FIQ_DMA9 (FIQ_START+INTERRUPT_DMA9) -+#define FIQ_DMA10 (FIQ_START+INTERRUPT_DMA10) -+#define FIQ_DMA11 (FIQ_START+INTERRUPT_DMA11) -+#define FIQ_DMA12 (FIQ_START+INTERRUPT_DMA12) -+#define FIQ_AUX (FIQ_START+INTERRUPT_AUX) -+#define FIQ_ARM (FIQ_START+INTERRUPT_ARM) -+#define FIQ_VPUDMA (FIQ_START+INTERRUPT_VPUDMA) -+#define FIQ_HOSTPORT (FIQ_START+INTERRUPT_HOSTPORT) -+#define FIQ_VIDEOSCALER (FIQ_START+INTERRUPT_VIDEOSCALER) -+#define FIQ_CCP2TX (FIQ_START+INTERRUPT_CCP2TX) -+#define FIQ_SDC (FIQ_START+INTERRUPT_SDC) -+#define FIQ_DSI0 (FIQ_START+INTERRUPT_DSI0) -+#define FIQ_AVE (FIQ_START+INTERRUPT_AVE) -+#define FIQ_CAM0 (FIQ_START+INTERRUPT_CAM0) -+#define FIQ_CAM1 (FIQ_START+INTERRUPT_CAM1) -+#define FIQ_HDMI0 (FIQ_START+INTERRUPT_HDMI0) -+#define FIQ_HDMI1 (FIQ_START+INTERRUPT_HDMI1) -+#define FIQ_PIXELVALVE1 (FIQ_START+INTERRUPT_PIXELVALVE1) -+#define FIQ_I2CSPISLV (FIQ_START+INTERRUPT_I2CSPISLV) -+#define FIQ_DSI1 (FIQ_START+INTERRUPT_DSI1) -+#define FIQ_PWA0 (FIQ_START+INTERRUPT_PWA0) -+#define FIQ_PWA1 (FIQ_START+INTERRUPT_PWA1) -+#define FIQ_CPR (FIQ_START+INTERRUPT_CPR) -+#define FIQ_SMI (FIQ_START+INTERRUPT_SMI) -+#define FIQ_GPIO0 (FIQ_START+INTERRUPT_GPIO0) -+#define FIQ_GPIO1 (FIQ_START+INTERRUPT_GPIO1) -+#define FIQ_GPIO2 (FIQ_START+INTERRUPT_GPIO2) -+#define FIQ_GPIO3 (FIQ_START+INTERRUPT_GPIO3) -+#define FIQ_I2C (FIQ_START+INTERRUPT_I2C) -+#define FIQ_SPI (FIQ_START+INTERRUPT_SPI) -+#define FIQ_I2SPCM (FIQ_START+INTERRUPT_I2SPCM) -+#define FIQ_SDIO (FIQ_START+INTERRUPT_SDIO) -+#define FIQ_UART (FIQ_START+INTERRUPT_UART) -+#define FIQ_SLIMBUS (FIQ_START+INTERRUPT_SLIMBUS) -+#define FIQ_VEC (FIQ_START+INTERRUPT_VEC) -+#define FIQ_CPG (FIQ_START+INTERRUPT_CPG) -+#define FIQ_RNG (FIQ_START+INTERRUPT_RNG) -+#define FIQ_ARASANSDIO (FIQ_START+INTERRUPT_ARASANSDIO) -+#define FIQ_AVSPMON (FIQ_START+INTERRUPT_AVSPMON) - --#define FIQ_ARM_TIMER INT_ARM_TIMER --#define FIQ_ARM_MAILBOX INT_ARM_MAILBOX --#define FIQ_ARM_DOORBELL_0 INT_ARM_DOORBELL_0 --#define FIQ_ARM_DOORBELL_1 INT_ARM_DOORBELL_1 --#define FIQ_VPU0_HALTED INT_VPU0_HALTED --#define FIQ_VPU1_HALTED INT_VPU1_HALTED --#define FIQ_ILLEGAL_TYPE0 INT_ILLEGAL_TYPE0 --#define FIQ_ILLEGAL_TYPE1 INT_ILLEGAL_TYPE1 --#define FIQ_PENDING1 INT_PENDING1 --#define FIQ_PENDING2 INT_PENDING2 -+#define FIQ_ARM_TIMER (FIQ_START+INTERRUPT_ARM_TIMER) -+#define FIQ_ARM_MAILBOX (FIQ_START+INTERRUPT_ARM_MAILBOX) -+#define FIQ_ARM_DOORBELL_0 (FIQ_START+INTERRUPT_ARM_DOORBELL_0) -+#define FIQ_ARM_DOORBELL_1 (FIQ_START+INTERRUPT_ARM_DOORBELL_1) -+#define FIQ_VPU0_HALTED (FIQ_START+INTERRUPT_VPU0_HALTED) -+#define FIQ_VPU1_HALTED (FIQ_START+INTERRUPT_VPU1_HALTED) -+#define FIQ_ILLEGAL_TYPE0 (FIQ_START+INTERRUPT_ILLEGAL_TYPE0) -+#define FIQ_ILLEGAL_TYPE1 (FIQ_START+INTERRUPT_ILLEGAL_TYPE1) -+#define FIQ_PENDING1 (FIQ_START+INTERRUPT_PENDING1) -+#define FIQ_PENDING2 (FIQ_START+INTERRUPT_PENDING2) - - #define HARD_IRQS (64 + 21) --#define GPIO_IRQ_START (HARD_IRQS) -+#define FIQ_IRQS (64 + 21) -+#define GPIO_IRQ_START (HARD_IRQS + FIQ_IRQS) - #define GPIO_IRQS (32*5) - #define SPARE_IRQS (64) --#define NR_IRQS (HARD_IRQS+GPIO_IRQS+SPARE_IRQS) -+#define NR_IRQS (HARD_IRQS+FIQ_IRQS+GPIO_IRQS+SPARE_IRQS) - - #endif /* _BCM2708_IRQS_H_ */ -diff --git a/arch/arm/mach-bcm2708/include/mach/platform.h b/arch/arm/mach-bcm2708/include/mach/platform.h -index f4bb733..992a630 100644 ---- a/arch/arm/mach-bcm2708/include/mach/platform.h -+++ b/arch/arm/mach-bcm2708/include/mach/platform.h -@@ -56,7 +56,9 @@ - */ - - #define BCM2708_PERI_BASE 0x20000000 -+#define IC0_BASE (BCM2708_PERI_BASE + 0x2000) - #define ST_BASE (BCM2708_PERI_BASE + 0x3000) /* System Timer */ -+#define MPHI_BASE (BCM2708_PERI_BASE + 0x6000) /* Message -based Parallel Host Interface */ - #define DMA_BASE (BCM2708_PERI_BASE + 0x7000) /* DMA controller */ - #define ARM_BASE (BCM2708_PERI_BASE + 0xB000) /* BCM2708 ARM control block */ - #define PM_BASE (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */ -diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile -index 236c47c..a56f193 100644 ---- a/drivers/usb/host/dwc_otg/Makefile -+++ b/drivers/usb/host/dwc_otg/Makefile -@@ -36,6 +36,7 @@ dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o - dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o - dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o - dwc_otg-objs += dwc_otg_adp.o -+dwc_otg-objs += dwc_otg_mphi_fix.o - ifneq ($(CFI),) - dwc_otg-objs += dwc_otg_cfi.o - endif -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -index 59fc862..096a3f1 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -@@ -45,6 +45,9 @@ - #include "dwc_otg_driver.h" - #include "dwc_otg_pcd.h" - #include "dwc_otg_hcd.h" -+#include "dwc_otg_mphi_fix.h" -+ -+extern bool fiq_fix_enable; - - #ifdef DEBUG - inline const char *op_state_str(dwc_otg_core_if_t * core_if) -@@ -1351,10 +1354,15 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if) - gintsts.d32, gintmsk.d32); - } - #endif -- if (gahbcfg.b.glblintrmsk) -+ if (!fiq_fix_enable){ -+ if (gahbcfg.b.glblintrmsk) -+ return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); -+ else -+ return 0; -+ } -+ else { - return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); -- else -- return 0; -+ } - - } - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_dbg.h b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h -index 8900318..ccc24e0 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_dbg.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h -@@ -49,6 +49,7 @@ static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new) - return old; - } - -+#define DBG_USER (0x1) - /** When debug level has the DBG_CIL bit set, display CIL Debug messages. */ - #define DBG_CIL (0x2) - /** When debug level has the DBG_CILV bit set, display CIL Verbose debug -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index ac2c846..97f150b 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -64,6 +64,8 @@ bool microframe_schedule=true; - - static const char dwc_driver_name[] = "dwc_otg"; - -+extern void* dummy_send; -+ - extern int pcd_init( - #ifdef LM_INTERFACE - struct lm_device *_dev -@@ -238,6 +240,10 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { - .adp_enable = -1, - }; - -+//Global variable to switch the fiq fix on or off (declared in bcm2708.c) -+extern bool fiq_fix_enable; -+ -+ - /** - * This function shows the Driver Version. - */ -@@ -779,17 +785,33 @@ static int dwc_otg_driver_probe( - _dev->resource->start, - _dev->resource->end - _dev->resource->start + 1); - #if 1 -- if (!request_mem_region(_dev->resource->start, -- _dev->resource->end - _dev->resource->start + 1, -+ if (!request_mem_region(_dev->resource[0].start, -+ _dev->resource[0].end - _dev->resource[0].start + 1, - "dwc_otg")) { - dev_dbg(&_dev->dev, "error reserving mapped memory\n"); - retval = -EFAULT; - goto fail; - } - -- dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource->start, -- _dev->resource->end - -- _dev->resource->start+1); -+ dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start, -+ _dev->resource[0].end - -+ _dev->resource[0].start+1); -+ if (fiq_fix_enable) -+ { -+ if (!request_mem_region(_dev->resource[1].start, -+ _dev->resource[1].end - _dev->resource[1].start + 1, -+ "dwc_otg")) { -+ dev_dbg(&_dev->dev, "error reserving mapped memory\n"); -+ retval = -EFAULT; -+ goto fail; -+ } -+ -+ dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start, -+ _dev->resource[1].end - -+ _dev->resource[1].start + 1); -+ dummy_send = (void *) kmalloc(16, GFP_ATOMIC); -+ } -+ - #else - { - struct map_desc desc = { -@@ -1063,6 +1085,7 @@ static int __init dwc_otg_driver_init(void) - printk(KERN_ERR "%s retval=%d\n", __func__, retval); - return retval; - } -+ printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled"); - - error = driver_create_file(drv, &driver_attr_version); - #ifdef DEBUG -@@ -1343,6 +1366,10 @@ MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0"); - module_param(microframe_schedule, bool, 0444); - MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler"); - -+ -+module_param(fiq_fix_enable, bool, 0444); -+MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix"); -+ - /** @page "Module Parameters" - * - * The following parameters may be specified when starting the module. -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index ab935c0..dd72d82 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -53,6 +53,8 @@ static int last_sel_trans_num_avail_hc_at_start = 0; - static int last_sel_trans_num_avail_hc_at_end = 0; - #endif /* DEBUG_HOST_CHANNELS */ - -+extern int g_next_sched_frame, g_np_count, g_np_sent; -+ - dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) - { - return DWC_ALLOC(sizeof(dwc_otg_hcd_t)); -@@ -407,6 +409,7 @@ static int dwc_otg_hcd_sleep_cb(void *p) - } - #endif - -+ - /** - * HCD Callback function for Remote Wakeup. - * -@@ -1330,6 +1333,8 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - &qh->qh_list_entry); - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - -+ g_np_sent++; -+ - if (ret_val == DWC_OTG_TRANSACTION_NONE) { - ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC; - } else { -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -index bb4f67a..e6d6293 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -@@ -594,7 +594,7 @@ extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, - /** @name Interrupt Handler Functions */ - /** @{ */ - extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); --extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd); -+extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd, int32_t); - extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * - dwc_otg_hcd); - extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h -index 4823167..fb57db0 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h -@@ -113,6 +113,11 @@ extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd); - */ - extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); - -+/** This function is used to handle the fast interrupt -+ * -+ */ -+extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void); -+ - /** - * Returns private data set by - * dwc_otg_hcd_set_priv_data function. -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index b41e164..b7b6b0c 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -34,6 +34,11 @@ - - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" -+#include "dwc_otg_mphi_fix.h" -+ -+#include -+#include -+ - - extern bool microframe_schedule; - -@@ -41,36 +46,105 @@ extern bool microframe_schedule; - * This file contains the implementation of the HCD Interrupt handlers. - */ - -+/* -+ * Some globals to communicate between the FIQ and INTERRUPT -+ */ -+ -+void * dummy_send; -+mphi_regs_t c_mphi_regs; -+int fiq_done, int_done; -+int g_next_sched_frame, g_np_count, g_np_sent, g_work_expected; -+static int mphi_int_count = 0 ; -+ -+extern bool fiq_fix_enable; -+ -+void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void) -+{ -+ gintsts_data_t gintsts; -+ hfnum_data_t hfnum; -+ -+ /* entry takes care to store registers we will be treading on here */ -+ asm __volatile__ ( -+ "mov ip, sp ;" -+ /* stash FIQ and normal regs */ -+ "stmdb sp!, {r0-r12, lr};" -+ /* !! THIS SETS THE FRAME, adjust to > sizeof locals */ -+ "sub fp, ip, #256 ;" -+ ); -+ -+ fiq_done++; -+ gintsts.d32 = FIQ_READ_IO_ADDRESS(USB_BASE + 0x14) & FIQ_READ_IO_ADDRESS(USB_BASE + 0x18); -+ hfnum.d32 = FIQ_READ_IO_ADDRESS(USB_BASE + 0x408); -+ -+ if(gintsts.d32) -+ { -+ if(gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) -+ { -+ /* -+ * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet -+ * g_next_sched_frame is the next frame we have periodic packets for -+ * -+ * if neither of these are required for this frame then just clear the interrupt -+ */ -+ gintsts.d32 = 0; -+ gintsts.b.sofintr = 1; -+ FIQ_WRITE_IO_ADDRESS((USB_BASE + 0x14), gintsts.d32); -+ -+ g_work_expected = 0; -+ } -+ else -+ { -+ g_work_expected = 1; -+ /* To enable the MPHI interrupt (INT 32) -+ */ -+ FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send); -+ FIQ_WRITE( c_mphi_regs.outddb, (1 << 29)); -+ -+ mphi_int_count++; -+ /* Clear the USB global interrupt so we don't just sit in the FIQ */ -+ FIQ_MODIFY_IO_ADDRESS((USB_BASE + 0x8),1,0); -+ -+ } -+ } -+ mb(); -+ -+ /* exit back to normal mode restoring everything */ -+ asm __volatile__ ( -+ /* return FIQ regs back to pristine state -+ * and get normal regs back -+ */ -+ "ldmia sp!, {r0-r12, lr};" -+ -+ /* return */ -+ "subs pc, lr, #4;" -+ ); -+} -+ - /** This function handles interrupts for the HCD. */ - int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - { - int retval = 0; -+ static int last_time; - - dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; - gintsts_data_t gintsts; -+ hfnum_data_t hfnum; -+ - #ifdef DEBUG - dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; - -- //GRAYG: debugging -- if (NULL == global_regs) { -- DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p " -- "core_if=%p\n", -- dwc_otg_hcd, global_regs); -- return retval; -- } - #endif - - /* Exit from ISR if core is hibernated */ - if (core_if->hibernation_suspend == 1) { -- return retval; -+ goto exit_handler_routine; - } - DWC_SPINLOCK(dwc_otg_hcd->lock); - /* Check if HOST Mode */ - if (dwc_otg_is_host_mode(core_if)) { - gintsts.d32 = dwc_otg_read_core_intr(core_if); - if (!gintsts.d32) { -- DWC_SPINUNLOCK(dwc_otg_hcd->lock); -- return 0; -+ goto exit_handler_routine; - } - #ifdef DEBUG - /* Don't print debug message in the interrupt handler on SOF */ -@@ -88,9 +162,14 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n", - gintsts.d32, core_if); - #endif -- -- if (gintsts.b.sofintr) { -- retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); -+ hfnum.d32 = DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum); -+ if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) -+ { -+ /* Note, we should never get here if the FIQ is doing it's job properly*/ -+ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd, g_work_expected); -+ } -+ else if (gintsts.b.sofintr) { -+ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd, g_work_expected); - } - if (gintsts.b.rxstsqlvl) { - retval |= -@@ -138,11 +217,37 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - #endif - - } -+ -+exit_handler_routine: -+ -+ if (fiq_fix_enable) -+ { -+ /* Clear the MPHI interrupt */ -+ DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16)); -+ if (mphi_int_count >= 60) -+ { -+ DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16))); -+ DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); -+ mphi_int_count = 0; -+ } -+ int_done++; -+ if((jiffies / HZ) > last_time) -+ { -+ /* Once a second output the fiq and irq numbers, useful for debug */ -+ last_time = jiffies / HZ; -+ DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done); -+ } -+ -+ /* Re-Enable FIQ interrupt from USB peripheral */ -+ DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1); -+ } -+ - DWC_SPINUNLOCK(dwc_otg_hcd->lock); - return retval; - } - - #ifdef DWC_TRACK_MISSED_SOFS -+ - #warning Compiling code to track missed SOFs - #define FRAME_NUM_ARRAY_SIZE 1000 - /** -@@ -182,13 +287,15 @@ static inline void track_missed_sofs(uint16_t curr_frame_number) - * (micro)frame. Periodic transactions may be queued to the controller for the - * next (micro)frame. - */ --int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) -+int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd, int32_t work_expected) - { - hfnum_data_t hfnum; - dwc_list_link_t *qh_entry; - dwc_otg_qh_t *qh; - dwc_otg_transaction_type_e tr_type; - gintsts_data_t gintsts = {.d32 = 0 }; -+ int did_something = 0; -+ int32_t next_sched_frame = -1; - - hfnum.d32 = - DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); -@@ -218,12 +325,30 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) - */ - DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, - &qh->qh_list_entry); -+ -+ did_something = 1; -+ } -+ else -+ { -+ if(next_sched_frame < 0 || dwc_frame_num_le(qh->sched_frame, next_sched_frame)) -+ { -+ next_sched_frame = qh->sched_frame; -+ } - } - } -+ -+ g_next_sched_frame = next_sched_frame; -+ - tr_type = dwc_otg_hcd_select_transactions(hcd); - if (tr_type != DWC_OTG_TRANSACTION_NONE) { - dwc_otg_hcd_queue_transactions(hcd, tr_type); -+ did_something = 1; - } -+ if(work_expected && !did_something) -+ DWC_DEBUGPL(DBG_USER, "Nothing to do !! frame = %x, g_next_sched_frame = %x\n", (int) hfnum.b.frnum, g_next_sched_frame); -+ if(!work_expected && did_something) -+ DWC_DEBUGPL(DBG_USER, "Unexpected work done !! frame = %x, g_next_sched_frame = %x\n", (int) hfnum.b.frnum, g_next_sched_frame); -+ - - /* Clear interrupt */ - gintsts.b.sofintr = 1; -@@ -2102,5 +2227,4 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - - return retval; - } -- - #endif /* DWC_DEVICE_ONLY */ -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index e4787f5..2b4a14e 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -1,3 +1,4 @@ -+ - /* ========================================================================== - * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $ - * $Revision: #20 $ -@@ -50,6 +51,7 @@ - #include - #include - #include -+#include - #include - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) - #include <../drivers/usb/core/hcd.h> -@@ -67,6 +69,8 @@ - #include "dwc_otg_dbg.h" - #include "dwc_otg_driver.h" - #include "dwc_otg_hcd.h" -+#include "dwc_otg_mphi_fix.h" -+ - /** - * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is - * qualified with its direction (possible 32 endpoints per device). -@@ -76,6 +80,8 @@ - - static const char dwc_otg_hcd_name[] = "dwc_otg_hcd"; - -+extern bool fiq_fix_enable; -+ - /** @name Linux HC Driver API Functions */ - /** @{ */ - /* manage i/o requests, device state */ -@@ -366,6 +372,12 @@ static struct dwc_otg_hcd_function_ops hcd_fops = { - .get_b_hnp_enable = _get_b_hnp_enable, - }; - -+static struct fiq_handler fh = { -+ .name = "usb_fiq", -+}; -+static uint8_t fiqStack[1024]; -+ -+extern mphi_regs_t c_mphi_regs; - /** - * Initializes the HCD. This function allocates memory for and initializes the - * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the -@@ -379,6 +391,7 @@ int hcd_init(dwc_bus_dev_t *_dev) - dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev); - int retval = 0; - u64 dmamask; -+ struct pt_regs regs; - - DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev); - -@@ -396,6 +409,18 @@ int hcd_init(dwc_bus_dev_t *_dev) - pci_set_consistent_dma_mask(_dev, dmamask); - #endif - -+ if (fiq_fix_enable) -+ { -+ // Set up fiq -+ claim_fiq(&fh); -+ set_fiq_handler(__FIQ_Branch, 4); -+ memset(®s,0,sizeof(regs)); -+ regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq; -+ regs.ARM_r9 = (long)0; -+ regs.ARM_sp = (long)fiqStack + sizeof(fiqStack) - 4; -+ set_fiq_regs(®s); -+ } -+ - /* - * Allocate memory for the base HCD plus the DWC OTG HCD. - * Initialize the base HCD. -@@ -415,6 +440,26 @@ int hcd_init(dwc_bus_dev_t *_dev) - - hcd->regs = otg_dev->os_dep.base; - -+ if (fiq_fix_enable) -+ { -+ //Set the mphi periph to the required registers -+ c_mphi_regs.base = otg_dev->os_dep.mphi_base; -+ c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; -+ c_mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28; -+ c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; -+ c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; -+ -+ //Enable mphi peripheral -+ writel((1<<31),c_mphi_regs.ctrl); -+#ifdef DEBUG -+ if (readl(c_mphi_regs.ctrl) & 0x80000000) -+ DWC_DEBUGPL(DBG_USER, "MPHI periph has been enabled\n"); -+ else -+ DWC_DEBUGPL(DBG_USER, "MPHI periph has NOT been enabled\n"); -+#endif -+ // Enable FIQ interrupt from USB peripheral -+ enable_fiq(INTERRUPT_VC_USB); -+ } - /* Initialize the DWC OTG HCD. */ - dwc_otg_hcd = dwc_otg_hcd_alloc_hcd(); - if (!dwc_otg_hcd) { -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index 9761566..a9dea55 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -572,6 +572,9 @@ static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - return status; - } - -+ -+extern int g_next_sched_frame, g_np_count, g_np_sent; -+ - /** - * Schedules an interrupt or isochronous transfer in the periodic schedule. - * -@@ -630,8 +633,13 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry); - } - else { -- /* Always start in the inactive schedule. */ -- DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry); -+ if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, g_next_sched_frame)) -+ { -+ g_next_sched_frame = qh->sched_frame; -+ -+ } -+ /* Always start in the inactive schedule. */ -+ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry); - } - - if (!microframe_schedule) { -@@ -645,6 +653,7 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - return status; - } - -+ - /** - * This function adds a QH to either the non periodic or periodic schedule if - * it is not already in the schedule. If the QH is already in the schedule, no -@@ -667,6 +676,7 @@ int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - /* Always start in the inactive schedule. */ - DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive, - &qh->qh_list_entry); -+ g_np_count++; - } else { - status = schedule_periodic(hcd, qh); - if ( !hcd->periodic_qh_count ) { -@@ -767,6 +777,7 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, - if (sched_next_periodic_split) { - - qh->sched_frame = frame_number; -+ - if (dwc_frame_num_le(frame_number, - dwc_frame_num_inc - (qh->start_split_frame, -@@ -815,6 +826,11 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, - DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, - &qh->qh_list_entry); - } else { -+ if(!dwc_frame_num_le(g_next_sched_frame, qh->sched_frame)) -+ { -+ g_next_sched_frame = qh->sched_frame; -+ } -+ - DWC_LIST_MOVE_HEAD - (&hcd->periodic_sched_inactive, - &qh->qh_list_entry); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c -new file mode 100755 -index 0000000..50b94a8 ---- /dev/null -+++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c -@@ -0,0 +1,113 @@ -+#include "dwc_otg_regs.h" -+#include "dwc_otg_dbg.h" -+ -+void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name) -+{ -+ DWC_DEBUGPL(DBG_USER, "*** Debugging from within the %s function: ***\n" -+ "curmode: %1i Modemismatch: %1i otgintr: %1i sofintr: %1i\n" -+ "rxstsqlvl: %1i nptxfempty : %1i ginnakeff: %1i goutnakeff: %1i\n" -+ "ulpickint: %1i i2cintr: %1i erlysuspend:%1i usbsuspend: %1i\n" -+ "usbreset: %1i enumdone: %1i isooutdrop: %1i eopframe: %1i\n" -+ "restoredone: %1i epmismatch: %1i inepint: %1i outepintr: %1i\n" -+ "incomplisoin:%1i incomplisoout:%1i fetsusp: %1i resetdet: %1i\n" -+ "portintr: %1i hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i\n" -+ "conidstschng:%1i disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", -+ function_name, -+ gintsts.b.curmode, -+ gintsts.b.modemismatch, -+ gintsts.b.otgintr, -+ gintsts.b.sofintr, -+ gintsts.b.rxstsqlvl, -+ gintsts.b.nptxfempty, -+ gintsts.b.ginnakeff, -+ gintsts.b.goutnakeff, -+ gintsts.b.ulpickint, -+ gintsts.b.i2cintr, -+ gintsts.b.erlysuspend, -+ gintsts.b.usbsuspend, -+ gintsts.b.usbreset, -+ gintsts.b.enumdone, -+ gintsts.b.isooutdrop, -+ gintsts.b.eopframe, -+ gintsts.b.restoredone, -+ gintsts.b.epmismatch, -+ gintsts.b.inepint, -+ gintsts.b.outepintr, -+ gintsts.b.incomplisoin, -+ gintsts.b.incomplisoout, -+ gintsts.b.fetsusp, -+ gintsts.b.resetdet, -+ gintsts.b.portintr, -+ gintsts.b.hcintr, -+ gintsts.b.ptxfempty, -+ gintsts.b.lpmtranrcvd, -+ gintsts.b.conidstschng, -+ gintsts.b.disconnect, -+ gintsts.b.sessreqintr, -+ gintsts.b.wkupintr); -+ return; -+} -+ -+void dwc_debug_core_int_mask(gintmsk_data_t gintmsk, const char* function_name) -+{ -+ DWC_DEBUGPL(DBG_USER, "Interrupt Mask status (called from %s) :\n" -+ "modemismatch: %1i otgintr: %1i sofintr: %1i rxstsqlvl: %1i\n" -+ "nptxfempty: %1i ginnakeff: %1i goutnakeff: %1i ulpickint: %1i\n" -+ "i2cintr: %1i erlysuspend:%1i usbsuspend: %1i usbreset: %1i\n" -+ "enumdone: %1i isooutdrop: %1i eopframe: %1i restoredone: %1i\n" -+ "epmismatch: %1i inepintr: %1i outepintr: %1i incomplisoin:%1i\n" -+ "incomplisoout:%1i fetsusp: %1i resetdet: %1i portintr: %1i\n" -+ "hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i conidstschng:%1i\n" -+ "disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", -+ function_name, -+ gintmsk.b.modemismatch, -+ gintmsk.b.otgintr, -+ gintmsk.b.sofintr, -+ gintmsk.b.rxstsqlvl, -+ gintmsk.b.nptxfempty, -+ gintmsk.b.ginnakeff, -+ gintmsk.b.goutnakeff, -+ gintmsk.b.ulpickint, -+ gintmsk.b.i2cintr, -+ gintmsk.b.erlysuspend, -+ gintmsk.b.usbsuspend, -+ gintmsk.b.usbreset, -+ gintmsk.b.enumdone, -+ gintmsk.b.isooutdrop, -+ gintmsk.b.eopframe, -+ gintmsk.b.restoredone, -+ gintmsk.b.epmismatch, -+ gintmsk.b.inepintr, -+ gintmsk.b.outepintr, -+ gintmsk.b.incomplisoin, -+ gintmsk.b.incomplisoout, -+ gintmsk.b.fetsusp, -+ gintmsk.b.resetdet, -+ gintmsk.b.portintr, -+ gintmsk.b.hcintr, -+ gintmsk.b.ptxfempty, -+ gintmsk.b.lpmtranrcvd, -+ gintmsk.b.conidstschng, -+ gintmsk.b.disconnect, -+ gintmsk.b.sessreqintr, -+ gintmsk.b.wkupintr); -+ return; -+} -+ -+void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name) -+{ -+ DWC_DEBUGPL(DBG_USER, "otg int register (from %s function):\n" -+ "sesenddet:%1i sesreqsucstschung:%2i hstnegsucstschng:%1i\n" -+ "hstnegdet:%1i adevtoutchng: %2i debdone: %1i\n" -+ "mvic: %1i\n", -+ function_name, -+ gotgint.b.sesenddet, -+ gotgint.b.sesreqsucstschng, -+ gotgint.b.hstnegsucstschng, -+ gotgint.b.hstnegdet, -+ gotgint.b.adevtoutchng, -+ gotgint.b.debdone, -+ gotgint.b.mvic); -+ -+ return; -+} -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -new file mode 100755 -index 0000000..660d50f ---- /dev/null -+++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -@@ -0,0 +1,36 @@ -+#ifndef __DWC_OTG_MPHI_FIX_H__ -+#define __DWC_OTG_MPHI_FIX_H__ -+ -+#define FIQ_WRITE_IO_ADDRESS(_addr_,_data_) *(volatile uint32_t *) IO_ADDRESS(_addr_) = _data_ -+#define FIQ_READ_IO_ADDRESS(_addr_) *(volatile uint32_t *) IO_ADDRESS(_addr_) -+#define FIQ_MODIFY_IO_ADDRESS(_addr_,_clear_,_set_) FIQ_WRITE_IO_ADDRESS(_addr_ , (FIQ_READ_IO_ADDRESS(_addr_)&~_clear_)|_set_) -+#define FIQ_WRITE(_addr_,_data_) *(volatile uint32_t *) _addr_ = _data_ -+ -+typedef struct { -+ volatile void* base; -+ volatile void* ctrl; -+ volatile void* outdda; -+ volatile void* outddb; -+ volatile void* intstat; -+} mphi_regs_t; -+ -+void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name); -+void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name); -+void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); -+ -+ -+ -+#ifdef DEBUG -+#define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__) -+#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) dwc_debug_core_int_mask(_arg_,__func__) -+#define DWC_DBG_PRINT_OTG_INT(_arg_) dwc_debug_otg_int(_arg_,__func__) -+ -+#else -+#define DWC_DBG_PRINT_CORE_INT(_arg_) -+#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) -+#define DWC_DBG_PRINT_OTG_INT(_arg_) -+ -+ -+#endif -+ -+#endif -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h -index e46d9bb..6b2c7d0 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h -@@ -97,6 +97,9 @@ typedef struct os_dependent { - /** Register offset for Diagnostic API */ - uint32_t reg_offset; - -+ /** Base address for MPHI peripheral */ -+ void *mphi_base; -+ - #ifdef LM_INTERFACE - struct lm_device *lmdev; - #elif defined(PCI_INTERFACE) --- -1.9.3 - - -From 52f15753484277644b3d65706bcf3a0f588f75a5 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sat, 8 Sep 2012 15:17:53 +0100 -Subject: [PATCH 021/124] Avoid dynamic memory allocation for channel lock in - USB driver. Thanks ddv2005. - ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 6 +++--- - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 2 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 3 +-- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 3 +-- - 4 files changed, 6 insertions(+), 8 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index dd72d82..c25db9a 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -822,6 +822,7 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) - } else if (dwc_otg_hcd->status_buf != NULL) { - DWC_FREE(dwc_otg_hcd->status_buf); - } -+ DWC_SPINLOCK_FREE(dwc_otg_hcd->channel_lock); - DWC_SPINLOCK_FREE(dwc_otg_hcd->lock); - /* Set core_if's lock pointer to NULL */ - dwc_otg_hcd->core_if->lock = NULL; -@@ -848,6 +849,7 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) - dwc_hc_t *channel; - - hcd->lock = DWC_SPINLOCK_ALLOC(); -+ hcd->channel_lock = DWC_SPINLOCK_ALLOC(); - DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n", - hcd, core_if); - if (!hcd->lock) { -@@ -1248,7 +1250,7 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - dwc_otg_qh_t *qh; - int num_channels; - dwc_irqflags_t flags; -- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC(); -+ dwc_spinlock_t *channel_lock = hcd->channel_lock; - dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; - - #ifdef DEBUG_SOF -@@ -1348,8 +1350,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - #ifdef DEBUG_HOST_CHANNELS - last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels; - #endif /* DEBUG_HOST_CHANNELS */ -- -- DWC_SPINLOCK_FREE(channel_lock); - return ret_val; - } - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -index e6d6293..f8ca2a4 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -@@ -548,7 +548,7 @@ struct dwc_otg_hcd { - - /* */ - dwc_spinlock_t *lock; -- -+ dwc_spinlock_t *channel_lock; - /** - * Private data that could be used by OS wrapper. - */ -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c -index 274967b..ee920c4 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c -@@ -276,7 +276,7 @@ void dump_frame_list(dwc_otg_hcd_t * hcd) - static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - { - dwc_irqflags_t flags; -- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC(); -+ dwc_spinlock_t *channel_lock = hcd->channel_lock; - - dwc_hc_t *hc = qh->channel; - if (dwc_qh_is_non_per(qh)) { -@@ -306,7 +306,6 @@ static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - dwc_memset(qh->desc_list, 0x00, - sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh)); - } -- DWC_SPINLOCK_FREE(channel_lock); - } - - /** -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index b7b6b0c..76b5085 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -922,7 +922,7 @@ static void release_channel(dwc_otg_hcd_t * hcd, - dwc_otg_transaction_type_e tr_type; - int free_qtd; - dwc_irqflags_t flags; -- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC(); -+ dwc_spinlock_t *channel_lock = hcd->channel_lock; - - DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", - __func__, hc->hc_num, halt_status, hc->xfer_len); -@@ -1009,7 +1009,6 @@ static void release_channel(dwc_otg_hcd_t * hcd, - if (tr_type != DWC_OTG_TRANSACTION_NONE) { - dwc_otg_hcd_queue_transactions(hcd, tr_type); - } -- DWC_SPINLOCK_FREE(channel_lock); - } - - /** --- -1.9.3 - - -From 7633321632fc5b99cd6bcb79f138dd085c2ac3ce Mon Sep 17 00:00:00 2001 +From d72219d3950210d8b498d78c9840bb97db504052 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 12 Apr 2013 23:58:47 +0100 -Subject: [PATCH 022/124] config: add missing options from 3.6.y kernel +Subject: [PATCH 23/53] config: add missing options from 3.6.y kernel --- - arch/arm/configs/bcmrpi_defconfig | 749 ++++++++++++++++++++++++++++++++------ - 1 file changed, 644 insertions(+), 105 deletions(-) + arch/arm/configs/bcmrpi_defconfig | 755 ++++++++++++++++++++++++++++++++------ + 1 file changed, 649 insertions(+), 106 deletions(-) diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 31f5afaa..bbf3000 100644 +index 31f5afaa..78d789c 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -1,11 +1,17 @@ @@ -92082,7 +91155,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_CGROUP_FREEZER=y -@@ -15,29 +21,43 @@ CONFIG_RESOURCE_COUNTERS=y +@@ -15,29 +21,42 @@ CONFIG_RESOURCE_COUNTERS=y CONFIG_BLK_CGROUP=y CONFIG_NAMESPACES=y CONFIG_SCHED_AUTOGROUP=y @@ -92114,7 +91187,7 @@ index 31f5afaa..bbf3000 100644 +CONFIG_CMA=y +CONFIG_UACCESS_WITH_MEMCPY=y CONFIG_SECCOMP=y - CONFIG_CC_STACKPROTECTOR=y +-CONFIG_CC_STACKPROTECTOR=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext3 rootwait" @@ -92131,7 +91204,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_BINFMT_MISC=m -@@ -48,19 +68,278 @@ CONFIG_XFRM_USER=y +@@ -48,19 +67,278 @@ CONFIG_XFRM_USER=y CONFIG_NET_KEY=m CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -92416,7 +91489,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_IRCOMM=m CONFIG_IRDA_ULTRA=y CONFIG_IRDA_CACHE_LAST_LSAP=y -@@ -73,8 +352,6 @@ CONFIG_USB_IRDA=m +@@ -73,8 +351,6 @@ CONFIG_USB_IRDA=m CONFIG_SIGMATEL_FIR=m CONFIG_MCS_FIR=m CONFIG_BT=m @@ -92425,7 +91498,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m -@@ -89,35 +366,103 @@ CONFIG_BT_HCIVHCI=m +@@ -89,35 +365,105 @@ CONFIG_BT_HCIVHCI=m CONFIG_BT_MRVL=m CONFIG_BT_MRVL_SDIO=m CONFIG_BT_ATH3K=m @@ -92444,6 +91517,8 @@ index 31f5afaa..bbf3000 100644 -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y ++CONFIG_DMA_CMA=y ++CONFIG_CMA_SIZE_MBYTES=5 CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_DRBD=m @@ -92537,7 +91612,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_LIBERTAS_THINFIRM=m CONFIG_LIBERTAS_THINFIRM_USB=m CONFIG_AT76C50X_USB=m -@@ -125,14 +470,17 @@ CONFIG_USB_ZD1201=m +@@ -125,14 +471,17 @@ CONFIG_USB_ZD1201=m CONFIG_USB_NET_RNDIS_WLAN=m CONFIG_RTL8187=m CONFIG_MAC80211_HWSIM=m @@ -92557,7 +91632,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_LIBERTAS=m CONFIG_LIBERTAS_USB=m CONFIG_LIBERTAS_SDIO=m -@@ -142,57 +490,28 @@ CONFIG_RT2X00=m +@@ -142,57 +491,28 @@ CONFIG_RT2X00=m CONFIG_RT2500USB=m CONFIG_RT73USB=m CONFIG_RT2800USB=m @@ -92623,7 +91698,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_INPUT_ATI_REMOTE2=m CONFIG_INPUT_KEYSPAN_REMOTE=m CONFIG_INPUT_POWERMATE=m -@@ -207,26 +526,191 @@ CONFIG_SERIO_RAW=m +@@ -207,26 +527,190 @@ CONFIG_SERIO_RAW=m CONFIG_GAMEPORT=m CONFIG_GAMEPORT_NS558=m CONFIG_GAMEPORT_L4=m @@ -92742,7 +91817,6 @@ index 31f5afaa..bbf3000 100644 +CONFIG_USB_ZR364XX=m +CONFIG_USB_STKWEBCAM=m +CONFIG_USB_S2255=m -+CONFIG_USB_SN9C102=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_TLG2300=m @@ -92801,11 +91875,11 @@ index 31f5afaa..bbf3000 100644 +CONFIG_RADIO_SI470X=y +CONFIG_USB_SI470X=m +CONFIG_I2C_SI470X=m ++CONFIG_RADIO_SI4713=m +CONFIG_USB_MR800=m +CONFIG_USB_DSBR=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m -+CONFIG_RADIO_SI4713=m +CONFIG_USB_KEENE=m +CONFIG_USB_MA901=m +CONFIG_RADIO_TEA5764=m @@ -92840,7 +91914,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_HID_ROCCAT=m CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m -@@ -292,15 +775,19 @@ CONFIG_HID_SUNPLUS=m +@@ -292,15 +775,20 @@ CONFIG_HID_SUNPLUS=m CONFIG_HID_GREENASIA=m CONFIG_HID_SMARTJOYPLUS=m CONFIG_HID_TOPSEED=m @@ -92848,6 +91922,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_HID_THRUSTMASTER=m CONFIG_HID_WACOM=m CONFIG_HID_WIIMOTE=m ++CONFIG_HID_XINMO=m CONFIG_HID_ZEROPLUS=m CONFIG_HID_ZYDACRON=m +CONFIG_HID_PID=y @@ -92860,7 +91935,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m CONFIG_USB_STORAGE_DATAFAB=m -@@ -315,8 +802,6 @@ CONFIG_USB_STORAGE_ONETOUCH=m +@@ -315,8 +803,6 @@ CONFIG_USB_STORAGE_ONETOUCH=m CONFIG_USB_STORAGE_KARMA=m CONFIG_USB_STORAGE_CYPRESS_ATACB=m CONFIG_USB_STORAGE_ENE_UB6250=m @@ -92869,7 +91944,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_USB_MDC800=m CONFIG_USB_MICROTEK=m CONFIG_USB_SERIAL=m -@@ -331,12 +816,12 @@ CONFIG_USB_SERIAL_CP210X=m +@@ -331,12 +817,12 @@ CONFIG_USB_SERIAL_CP210X=m CONFIG_USB_SERIAL_CYPRESS_M8=m CONFIG_USB_SERIAL_EMPEG=m CONFIG_USB_SERIAL_FTDI_SIO=m @@ -92883,7 +91958,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_USB_SERIAL_GARMIN=m CONFIG_USB_SERIAL_IPW=m CONFIG_USB_SERIAL_IUU=m -@@ -345,18 +830,16 @@ CONFIG_USB_SERIAL_KEYSPAN=m +@@ -345,18 +831,16 @@ CONFIG_USB_SERIAL_KEYSPAN=m CONFIG_USB_SERIAL_KLSI=m CONFIG_USB_SERIAL_KOBIL_SCT=m CONFIG_USB_SERIAL_MCT_U232=m @@ -92903,7 +91978,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_USB_SERIAL_SIERRAWIRELESS=m CONFIG_USB_SERIAL_SYMBOL=m CONFIG_USB_SERIAL_TI=m -@@ -365,9 +848,11 @@ CONFIG_USB_SERIAL_XIRCOM=m +@@ -365,9 +849,11 @@ CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_OPTION=m CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_OPTICON=m @@ -92917,7 +91992,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_USB_SERIAL_DEBUG=m CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m -@@ -389,17 +874,71 @@ CONFIG_USB_TEST=m +@@ -389,17 +875,74 @@ CONFIG_USB_TEST=m CONFIG_USB_ISIGHTFW=m CONFIG_USB_YUREX=m CONFIG_MMC=y @@ -92951,7 +92026,9 @@ index 31f5afaa..bbf3000 100644 +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_ISL12022=m ++CONFIG_RTC_DRV_ISL12057=m +CONFIG_RTC_DRV_X1205=m ++CONFIG_RTC_DRV_PCF2127=m +CONFIG_RTC_DRV_PCF8523=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m @@ -92985,6 +92062,7 @@ index 31f5afaa..bbf3000 100644 +CONFIG_SPEAKUP_SYNTH_SOFT=m +CONFIG_STAGING_MEDIA=y +CONFIG_DVB_AS102=m ++CONFIG_USB_SN9C102=m +CONFIG_LIRC_STAGING=y +CONFIG_LIRC_IGORPLUGUSB=m +CONFIG_LIRC_IMON=m @@ -92994,7 +92072,7 @@ index 31f5afaa..bbf3000 100644 # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y -@@ -422,6 +961,8 @@ CONFIG_BTRFS_FS=m +@@ -422,6 +965,8 @@ CONFIG_BTRFS_FS=m CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_FANOTIFY=y @@ -93003,7 +92081,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_AUTOFS4_FS=y CONFIG_FUSE_FS=m CONFIG_CUSE=m -@@ -437,28 +978,32 @@ CONFIG_MSDOS_FS=y +@@ -437,28 +982,32 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_NTFS_FS=m @@ -93040,7 +92118,7 @@ index 31f5afaa..bbf3000 100644 CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=m -@@ -497,39 +1042,33 @@ CONFIG_NLS_ISO8859_14=m +@@ -497,39 +1046,33 @@ CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m @@ -93096,834 +92174,10 @@ index 31f5afaa..bbf3000 100644 1.9.3 -From fb7ac42d7c8ce3169dee557cde1f0ca585688483 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 8 Apr 2013 21:12:48 +0100 -Subject: [PATCH 023/124] Add NAK holdoff scheme. Enabled by default, disable - with dwc_otg.nak_holdoff_enable=0. Thanks gsh - ---- - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 7 ++++++- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 22 +++++++++++++++++++++- - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 5 +++++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 21 +++++++++++++++++++-- - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 19 +++++++++++++++++++ - 5 files changed, 70 insertions(+), 4 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index 97f150b..c2bb596 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -243,6 +243,9 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { - //Global variable to switch the fiq fix on or off (declared in bcm2708.c) - extern bool fiq_fix_enable; - -+//Global variable to switch the nak holdoff on or off -+bool nak_holdoff_enable = true; -+ - - /** - * This function shows the Driver Version. -@@ -1086,6 +1089,7 @@ static int __init dwc_otg_driver_init(void) - return retval; - } - printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled"); -+ printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled"); - - error = driver_create_file(drv, &driver_attr_version); - #ifdef DEBUG -@@ -1366,9 +1370,10 @@ MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0"); - module_param(microframe_schedule, bool, 0444); - MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler"); - -- - module_param(fiq_fix_enable, bool, 0444); - MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix"); -+module_param(nak_holdoff_enable, bool, 0444); -+MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff"); - - /** @page "Module Parameters" - * -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index c25db9a..7f610d5 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -527,6 +527,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, - { - dwc_otg_qh_t *qh; - dwc_otg_qtd_t *urb_qtd; -+ BUG_ON(!hcd); -+ BUG_ON(!dwc_otg_urb); - - #ifdef DEBUG /* integrity checks (Broadcom) */ - -@@ -543,14 +545,17 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, - return -DWC_E_INVALID; - } - urb_qtd = dwc_otg_urb->qtd; -+ BUG_ON(!urb_qtd); - if (urb_qtd->qh == NULL) { - DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n"); - return -DWC_E_INVALID; - } - #else - urb_qtd = dwc_otg_urb->qtd; -+ BUG_ON(!urb_qtd); - #endif - qh = urb_qtd->qh; -+ BUG_ON(!qh); - if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { - if (urb_qtd->in_process) { - dump_channel_info(hcd, qh); -@@ -1309,6 +1314,22 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - num_channels - hcd->periodic_channels) && - !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { - -+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ -+ /* -+ * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission -+ * we hold off on bulk retransmissions to reduce NAK interrupt overhead for -+ * cheeky devices that just hold off using NAKs -+ */ -+ if (dwc_full_frame_num(qh->nak_frame) == dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { -+ // Make fiq interrupt run on next frame (i.e. 8 uframes) -+ g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; -+ qh_ptr = DWC_LIST_NEXT(qh_ptr); -+ continue; -+ } -+ else -+ qh->nak_frame = 0xffff; -+ - if (microframe_schedule) { - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - if (hcd->available_host_channels < 1) { -@@ -1321,7 +1342,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - last_sel_trans_num_nonper_scheduled++; - #endif /* DEBUG_HOST_CHANNELS */ - } -- qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - - assign_and_init_hc(hcd, qh); - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -index f8ca2a4..0827b19 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -@@ -321,6 +321,11 @@ typedef struct dwc_otg_qh { - */ - uint16_t sched_frame; - -+ /* -+ ** Frame a NAK was received on this queue head, used to minimise NAK retransmission -+ */ -+ uint16_t nak_frame; -+ - /** (micro)frame at which last start split was initialized. */ - uint16_t start_split_frame; - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 76b5085..aff59df 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -56,7 +56,12 @@ int fiq_done, int_done; - int g_next_sched_frame, g_np_count, g_np_sent, g_work_expected; - static int mphi_int_count = 0 ; - --extern bool fiq_fix_enable; -+extern bool fiq_fix_enable, nak_holdoff_enable; -+ -+hcchar_data_t nak_hcchar; -+hctsiz_data_t nak_hctsiz; -+hcsplt_data_t nak_hcsplt; -+int nak_count; - - void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void) - { -@@ -230,7 +235,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); - mphi_int_count = 0; - } -- int_done++; -+ int_done++; - if((jiffies / HZ) > last_time) - { - /* Once a second output the fiq and irq numbers, useful for debug */ -@@ -1419,6 +1424,18 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, - "NAK Received--\n", hc->hc_num); - - /* -+ * When we get bulk NAKs then remember this so we holdoff on this qh until -+ * the beginning of the next frame -+ */ -+ switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { -+ case UE_BULK: -+ //case UE_INTERRUPT: -+ //case UE_CONTROL: -+ if (nak_holdoff_enable) -+ hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd); -+ } -+ -+ /* - * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and - * interrupt. Re-start the SSPLIT transfer. - */ -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index a9dea55..ebee73a 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -181,6 +181,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) - if (microframe_schedule) - qh->speed = dev_speed; - -+ qh->nak_frame = 0xffff; - - if (((dev_speed == USB_SPEED_LOW) || - (dev_speed == USB_SPEED_FULL)) && -@@ -764,6 +765,24 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, - int sched_next_periodic_split) - { - if (dwc_qh_is_non_per(qh)) { -+ -+ dwc_otg_qh_t *qh_tmp; -+ dwc_list_link_t *qh_list; -+ DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) -+ { -+ qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); -+ if(qh_tmp == qh) -+ { -+ /* -+ * FIQ is being disabled because this one nevers gets a np_count increment -+ * This is still not absolutely correct, but it should fix itself with -+ * just an unnecessary extra interrupt -+ */ -+ g_np_sent = g_np_count; -+ } -+ } -+ -+ - dwc_otg_hcd_qh_remove(hcd, qh); - if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { - /* Add back to inactive non-periodic schedule. */ --- -1.9.3 - - -From a780a572c1ff18aa11ee73c2a4c5deb3ca87b1ad Mon Sep 17 00:00:00 2001 -From: Gordon Hollingworth -Date: Sun, 4 Nov 2012 15:55:01 +0000 -Subject: [PATCH 024/124] Make sure we wait for the reset to finish - ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index aff59df..1a23d4b 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -232,6 +232,8 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - if (mphi_int_count >= 60) - { - DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16))); -+ while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17))) -+ ; - DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); - mphi_int_count = 0; - } --- -1.9.3 - - -From 6ad87474dd7b76c1b058c21fec5f2c38227dff40 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Wed, 9 Jan 2013 16:12:04 +0000 -Subject: [PATCH 025/124] dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent - kernel memory corruption, escalating to OOPS under high USB load. - ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 2 -- - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 1 + - 2 files changed, 1 insertion(+), 2 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 7f610d5..9d30a59 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -500,8 +500,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. " - "Error status %d\n", retval); - dwc_otg_hcd_qtd_free(qtd); -- } else { -- qtd->qh = *ep_handle; - } - intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); - if (!intr_mask.b.sofintr && retval == 0) { -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index ebee73a..b3efaf4 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -946,6 +946,7 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, - if (retval == 0) { - DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd, - qtd_list_entry); -+ qtd->qh = *qh; - } - DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); - --- -1.9.3 - - -From 95ee557496eca77271e1721e1bdf4ea864c4539c Mon Sep 17 00:00:00 2001 -From: P33M -Date: Fri, 15 Feb 2013 22:36:47 +0000 -Subject: [PATCH 026/124] dwc_otg: Fix unsafe access of QTD during URB enqueue - -In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the -transaction could complete almost immediately after the qtd was assigned -to a host channel during URB enqueue, which meant the qtd pointer was no -longer valid having been completed and removed. Usually, this resulted in -an OOPS during URB submission. By predetermining whether transactions -need to be queued or not, this unsafe pointer access is avoided. - -This bug was only evident on the Pi model A where a device was attached -that had no periodic endpoints (e.g. USB pendrive or some wlan devices). ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 23 ++++++++++++----------- - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 2 +- - 2 files changed, 13 insertions(+), 12 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 9d30a59..35d03d1 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -462,6 +462,8 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - { - dwc_irqflags_t flags; - int retval = 0; -+ uint8_t needs_scheduling = 0; -+ dwc_otg_transaction_type_e tr_type; - dwc_otg_qtd_t *qtd; - gintmsk_data_t intr_mask = {.d32 = 0 }; - -@@ -493,22 +495,22 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - return -DWC_E_NO_MEMORY; - } - #endif -- retval = -- dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc); -+ intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); -+ if(!intr_mask.b.sofintr) needs_scheduling = 1; -+ if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) -+ /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */ -+ needs_scheduling = 0; -+ -+ retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc); - // creates a new queue in ep_handle if it doesn't exist already - if (retval < 0) { - DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. " - "Error status %d\n", retval); - dwc_otg_hcd_qtd_free(qtd); -+ return retval; - } -- intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); -- if (!intr_mask.b.sofintr && retval == 0) { -- dwc_otg_transaction_type_e tr_type; -- if ((qtd->qh->ep_type == UE_BULK) -- && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) { -- /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */ -- return 0; -- } -+ -+ if(needs_scheduling) { - DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); - tr_type = dwc_otg_hcd_select_transactions(hcd); - if (tr_type != DWC_OTG_TRANSACTION_NONE) { -@@ -516,7 +518,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - } - DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); - } -- - return retval; - } - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index b3efaf4..1554be5 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -937,7 +937,7 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, - if (*qh == NULL) { - *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc); - if (*qh == NULL) { -- retval = -1; -+ retval = -DWC_E_NO_MEMORY; - goto done; - } - } --- -1.9.3 - - -From d39acc0ac191544120b28bbf6436cd713d9244b1 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Fri, 15 Feb 2013 22:38:40 +0000 -Subject: [PATCH 027/124] dwc_otg: Fix incorrect URB allocation error handling - -If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS -because for some reason a member of the *unallocated* struct was set to -zero. Error handling changed to fail correctly. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 16 ++++++---------- - 1 file changed, 6 insertions(+), 10 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 35d03d1..6fe30e3 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -3136,17 +3136,13 @@ dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd, - else - dwc_otg_urb = DWC_ALLOC(size); - -- if (NULL != dwc_otg_urb) -- dwc_otg_urb->packet_count = iso_desc_count; -+ if (dwc_otg_urb) -+ dwc_otg_urb->packet_count = iso_desc_count; - else { -- dwc_otg_urb->packet_count = 0; -- if (size != 0) { -- DWC_ERROR("**** DWC OTG HCD URB alloc - " -- "%salloc of %db failed\n", -- atomic_alloc?"atomic ":"", size); -- } -- } -- -+ DWC_ERROR("**** DWC OTG HCD URB alloc - " -+ "%salloc of %db failed\n", -+ atomic_alloc?"atomic ":"", size); -+ } - return dwc_otg_urb; - } - --- -1.9.3 - - -From 31ef2986fcdff62f1b8472939bd5df4aa69cf9ee Mon Sep 17 00:00:00 2001 -From: P33M -Date: Thu, 28 Feb 2013 16:52:51 +0000 -Subject: [PATCH 028/124] dwc_otg: fix potential use-after-free case in - interrupt handler - -If a transaction had previously aborted, certain interrupts are -enabled to track error counts and reset where necessary. On IN -endpoints the host generates an ACK interrupt near-simultaneously -with completion of transfer. In the case where this transfer had -previously had an error, this results in a use-after-free on -the QTD memory space with a 1-byte length being overwritten to -0x00. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 1a23d4b..7af455d 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -2223,7 +2223,8 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd); - } - if (hcint.b.ack) { -- retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd); -+ if(!hcint.b.chhltd) -+ retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd); - } - if (hcint.b.nyet) { - retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd); --- -1.9.3 - - -From 763c2e5d78c487f3d021b72a99f6f52ed92cc89c Mon Sep 17 00:00:00 2001 -From: P33M -Date: Sun, 3 Mar 2013 14:45:53 +0000 -Subject: [PATCH 029/124] dwc_otg: add handling of SPLIT transaction data - toggle errors - -Previously a data toggle error on packets from a USB1.1 device behind -a TT would result in the Pi locking up as the driver never handled -the associated interrupt. Patch adds basic retry mechanism and -interrupt acknowledgement to cater for either a chance toggle error or -for devices that have a broken initial toggle state (FT8U232/FT232BM). ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 19 ++++++++++++++----- - 1 file changed, 14 insertions(+), 5 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 7af455d..a27dacd 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -1921,13 +1921,20 @@ static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd, - dwc_otg_qtd_t * qtd) - { - DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " -- "Data Toggle Error--\n", hc->hc_num); -+ "Data Toggle Error on %s transfer--\n", -+ hc->hc_num, (hc->ep_is_in ? "IN" : "OUT")); - -- if (hc->ep_is_in) { -+ /* Data toggles on split transactions cause the hc to halt. -+ * restart transfer */ -+ if(hc->qh->do_split) -+ { -+ qtd->error_count++; -+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); -+ update_urb_state_xfer_intr(hc, hc_regs, -+ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); -+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); -+ } else if (hc->ep_is_in) { - qtd->error_count = 0; -- } else { -- DWC_ERROR("Data Toggle Error on OUT transfer," -- "channel %d\n", hc->hc_num); - } - - disable_hc_int(hc_regs, datatglerr); -@@ -2080,6 +2087,8 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - handle_hc_babble_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.frmovrun) { - handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd); -+ } else if (hcint.b.datatglerr) { -+ handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd); - } else if (!out_nak_enh) { - if (hcint.b.nyet) { - /* --- -1.9.3 - - -From fded772aeb2cb5552ef8bc4476dcb16405036925 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Thu, 21 Mar 2013 19:36:17 +0000 -Subject: [PATCH 030/124] dwc_otg: implement tasklet for returning URBs to - usbcore hcd layer - -The dwc_otg driver interrupt handler for transfer completion will spend -a very long time with interrupts disabled when a URB is completed - -this is because usb_hcd_giveback_urb is called from within the handler -which for a USB device driver with complicated processing (e.g. webcam) -will take an exorbitant amount of time to complete. This results in -missed completion interrupts for other USB packets which lead to them -being dropped due to microframe overruns. - -This patch splits returning the URB to the usb hcd layer into a -high-priority tasklet. This will have most benefit for isochronous IN -transfers but will also have incidental benefit where multiple periodic -devices are active at once. ---- - .../usb/host/dwc_common_port/dwc_common_linux.c | 5 ++++ - drivers/usb/host/dwc_common_port/dwc_list.h | 14 ++++----- - drivers/usb/host/dwc_common_port/dwc_os.h | 2 ++ - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 34 +++++++++++++++++++++- - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 10 +++++++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 25 ++++++++++------ - 6 files changed, 73 insertions(+), 17 deletions(-) - -diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -index 440bcfc..1788812 100644 ---- a/drivers/usb/host/dwc_common_port/dwc_common_linux.c -+++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -@@ -991,6 +991,11 @@ void DWC_TASK_SCHEDULE(dwc_tasklet_t *task) - tasklet_schedule(&task->t); - } - -+void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task) -+{ -+ tasklet_hi_schedule(&task->t); -+} -+ - - /* workqueues - - run in process context (can sleep) -diff --git a/drivers/usb/host/dwc_common_port/dwc_list.h b/drivers/usb/host/dwc_common_port/dwc_list.h -index 89cc325..4ce560d 100644 ---- a/drivers/usb/host/dwc_common_port/dwc_list.h -+++ b/drivers/usb/host/dwc_common_port/dwc_list.h -@@ -384,17 +384,17 @@ struct { \ - #define DWC_TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - #define DWC_TAILQ_EMPTY(head) \ -- (TAILQ_FIRST(head) == TAILQ_END(head)) -+ (DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head)) - - #define DWC_TAILQ_FOREACH(var, head, field) \ -- for((var) = TAILQ_FIRST(head); \ -- (var) != TAILQ_END(head); \ -- (var) = TAILQ_NEXT(var, field)) -+ for ((var) = DWC_TAILQ_FIRST(head); \ -+ (var) != DWC_TAILQ_END(head); \ -+ (var) = DWC_TAILQ_NEXT(var, field)) - - #define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \ -- for((var) = TAILQ_LAST(head, headname); \ -- (var) != TAILQ_END(head); \ -- (var) = TAILQ_PREV(var, headname, field)) -+ for ((var) = DWC_TAILQ_LAST(head, headname); \ -+ (var) != DWC_TAILQ_END(head); \ -+ (var) = DWC_TAILQ_PREV(var, headname, field)) - - /* - * Tail queue functions. -diff --git a/drivers/usb/host/dwc_common_port/dwc_os.h b/drivers/usb/host/dwc_common_port/dwc_os.h -index 9ffe929..09ed244 100644 ---- a/drivers/usb/host/dwc_common_port/dwc_os.h -+++ b/drivers/usb/host/dwc_common_port/dwc_os.h -@@ -981,6 +981,8 @@ extern void DWC_TASK_FREE(dwc_tasklet_t *task); - extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task); - #define dwc_task_schedule DWC_TASK_SCHEDULE - -+extern void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task); -+#define dwc_task_hi_schedule DWC_TASK_HI_SCHEDULE - - /** @name Timer - * -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 6fe30e3..533b17d 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -40,6 +40,9 @@ - * header file. - */ - -+#include -+#include -+ - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" - -@@ -694,6 +697,31 @@ static void reset_tasklet_func(void *data) - dwc_otg_hcd->flags.b.port_reset_change = 1; - } - -+static void completion_tasklet_func(void *ptr) -+{ -+ dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr; -+ struct urb *urb; -+ urb_tq_entry_t *item; -+ dwc_irqflags_t flags; -+ -+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); -+ while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) { -+ item = DWC_TAILQ_FIRST(&hcd->completed_urb_list); -+ urb = item->urb; -+ DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item, -+ urb_tq_entries); -+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); -+ DWC_FREE(item); -+ -+ usb_hcd_unlink_urb_from_ep(hcd->priv, urb); -+ usb_hcd_giveback_urb(hcd->priv, urb, urb->status); -+ -+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); -+ } -+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); -+ return; -+} -+ - static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) - { - dwc_list_link_t *item; -@@ -833,6 +861,7 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) - - DWC_TIMER_FREE(dwc_otg_hcd->conn_timer); - DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet); -+ DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet); - - #ifdef DWC_DEV_SRPCAP - if (dwc_otg_hcd->core_if->power_down == 2 && -@@ -877,7 +906,7 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) - DWC_LIST_INIT(&hcd->periodic_sched_ready); - DWC_LIST_INIT(&hcd->periodic_sched_assigned); - DWC_LIST_INIT(&hcd->periodic_sched_queued); -- -+ DWC_TAILQ_INIT(&hcd->completed_urb_list); - /* - * Create a host channel descriptor for each host channel implemented - * in the controller. Initialize the channel descriptor array. -@@ -915,6 +944,9 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) - - /* Initialize reset tasklet. */ - hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd); -+ -+ hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet", -+ completion_tasklet_func, hcd); - #ifdef DWC_DEV_SRPCAP - if (hcd->core_if->power_down == 2) { - /* Initialize Power on timer for Host power up in case hibernation */ -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -index 0827b19..0ba7558 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -@@ -374,6 +374,13 @@ typedef struct dwc_otg_qh { - - DWC_CIRCLEQ_HEAD(hc_list, dwc_hc); - -+typedef struct urb_tq_entry { -+ struct urb *urb; -+ DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries; -+} urb_tq_entry_t; -+ -+DWC_TAILQ_HEAD(urb_list, urb_tq_entry); -+ - /** - * This structure holds the state of the HCD, including the non-periodic and - * periodic schedules. -@@ -551,6 +558,9 @@ struct dwc_otg_hcd { - /* Tasket to do a reset */ - dwc_tasklet_t *reset_tasklet; - -+ dwc_tasklet_t *completion_tasklet; -+ struct urb_list completed_urb_list; -+ - /* */ - dwc_spinlock_t *lock; - dwc_spinlock_t *channel_lock; -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index 2b4a14e..39787e3 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -271,7 +271,7 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, - dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status) - { - struct urb *urb = (struct urb *)urb_handle; -- -+ urb_tq_entry_t *new_entry; - if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { - DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n", - __func__, urb, usb_pipedevice(urb->pipe), -@@ -285,7 +285,7 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, - } - } - } -- -+ new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t)); - urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb); - /* Convert status value. */ - switch (status) { -@@ -348,18 +348,25 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, - } - - DWC_FREE(dwc_otg_urb); -- -+ if (!new_entry) { -+ DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n"); -+ urb->status = -EPROTO; -+ /* don't schedule the tasklet - -+ * directly return the packet here with error. */ - #if USB_URB_EP_LINKING -- usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); -+ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); - #endif -- DWC_SPINUNLOCK(hcd->lock); - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -- usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); -+ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); - #else -- usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status); -+ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); - #endif -- DWC_SPINLOCK(hcd->lock); -- -+ } else { -+ new_entry->urb = urb; -+ DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry, -+ urb_tq_entries); -+ DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet); -+ } - return 0; - } - --- -1.9.3 - - -From 145215177d7d7b4a97563bfdeadc9989309a127f Mon Sep 17 00:00:00 2001 -From: P33M -Date: Mon, 22 Apr 2013 00:08:36 +0100 -Subject: [PATCH 032/124] dwc_otg: fix NAK holdoff and allow on split - transactions only - -This corrects a bug where if a single active non-periodic endpoint -had at least one transaction in its qh, on frnum == MAX_FRNUM the qh -would get skipped and never get queued again. This would result in -a silent device until error detection (automatic or otherwise) would -either reset the device or flush and requeue the URBs. - -Additionally the NAK holdoff was enabled for all transactions - this -would potentially stall a HS endpoint for 1ms if a previous error state -enabled this interrupt and the next response was a NAK. Fix so that -only split transactions get held off. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 28 ++++++++++++++++++---------- - 1 file changed, 18 insertions(+), 10 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 533b17d..73f7643 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -46,7 +46,7 @@ - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" - --extern bool microframe_schedule; -+extern bool microframe_schedule, nak_holdoff_enable; - - //#define DEBUG_HOST_CHANNELS - #ifdef DEBUG_HOST_CHANNELS -@@ -1349,18 +1349,26 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - - /* - * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission -- * we hold off on bulk retransmissions to reduce NAK interrupt overhead for -+ * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed - * cheeky devices that just hold off using NAKs - */ -- if (dwc_full_frame_num(qh->nak_frame) == dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { -- // Make fiq interrupt run on next frame (i.e. 8 uframes) -- g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; -- qh_ptr = DWC_LIST_NEXT(qh_ptr); -- continue; -+ if (nak_holdoff_enable && qh->do_split) { -+ if (qh->nak_frame != 0xffff && -+ dwc_full_frame_num(qh->nak_frame) == -+ dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { -+ /* -+ * Revisit: Need to avoid trampling on periodic scheduling. -+ * Currently we are safe because g_np_count != g_np_sent whenever we hit this, -+ * but if this behaviour is changed then periodic endpoints will get a slower -+ * polling rate. -+ */ -+ g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; -+ qh_ptr = DWC_LIST_NEXT(qh_ptr); -+ continue; -+ } else { -+ qh->nak_frame = 0xffff; -+ } - } -- else -- qh->nak_frame = 0xffff; -- - if (microframe_schedule) { - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - if (hcd->available_host_channels < 1) { --- -1.9.3 - - -From 8bec6fb9212e63e6c1925d6c5e7cf465aff80580 Mon Sep 17 00:00:00 2001 +From 4c248291b0bf90de3eabc221912f7f865a64d0c6 Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 033/124] Speed up console framebuffer imageblit function +Subject: [PATCH 24/53] Speed up console framebuffer imageblit function Especially on platforms with a slower CPU but a relatively high framebuffer fill bandwidth, like current ARM devices, the existing @@ -93951,13 +92205,13 @@ the greater benefit for 32bpp. Signed-off-by: Harm Hanemaaijer --- - drivers/video/cfbimgblt.c | 152 ++++++++++++++++++++++++++++++++++++++++++++-- + drivers/video/fbdev/core/cfbimgblt.c | 152 +++++++++++++++++++++++++++++++++-- 1 file changed, 147 insertions(+), 5 deletions(-) -diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c +diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c index a2bb276..436494f 100644 ---- a/drivers/video/cfbimgblt.c -+++ b/drivers/video/cfbimgblt.c +--- a/drivers/video/fbdev/core/cfbimgblt.c ++++ b/drivers/video/fbdev/core/cfbimgblt.c @@ -28,6 +28,11 @@ * * Also need to add code to deal with cards endians that are different than @@ -94135,10 +92389,10 @@ index a2bb276..436494f 100644 1.9.3 -From ddc7b0941ab7e87376fa8cacb13a12efab7172d6 Mon Sep 17 00:00:00 2001 +From 81f1e729fa271a57a4819630a36baca3cb354402 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 034/124] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 25/53] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -94148,14 +92402,14 @@ is hardware accelerated (otherwide it does not make any sense). Signed-off-by: Siarhei Siamashka --- - drivers/video/fbmem.c | 30 ++++++++++++++++++++++++++++++ - include/uapi/linux/fb.h | 5 +++++ + drivers/video/fbdev/core/fbmem.c | 30 ++++++++++++++++++++++++++++++ + include/uapi/linux/fb.h | 5 +++++ 2 files changed, 35 insertions(+) -diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c -index 7309ac7..46984cc 100644 ---- a/drivers/video/fbmem.c -+++ b/drivers/video/fbmem.c +diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c +index b6d5008..0ae8e96 100644 +--- a/drivers/video/fbdev/core/fbmem.c ++++ b/drivers/video/fbdev/core/fbmem.c @@ -1083,6 +1083,25 @@ fb_blank(struct fb_info *info, int blank) } EXPORT_SYMBOL(fb_blank); @@ -94234,10 +92488,10 @@ index fb795c3..fa72af0 100644 1.9.3 -From 2ae7811e0eff7b8e0a6ce5314c463ac39c5afdf8 Mon Sep 17 00:00:00 2001 +From 42863cf4409f763fcb9c1d48b631c80bf7cdaff3 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 16:00:25 +0300 -Subject: [PATCH 035/124] bcm2708_fb: DMA acceleration for fb_copyarea +Subject: [PATCH 26/53] bcm2708_fb: DMA acceleration for fb_copyarea Based on http://www.raspberrypi.org/phpBB3/viewtopic.php?p=62425#p62425 Also used Simon's dmaer_master module as a reference for tweaking DMA @@ -94276,7 +92530,7 @@ Signed-off-by: Luke Diamand --- arch/arm/mach-bcm2708/dma.c | 8 + arch/arm/mach-bcm2708/include/mach/dma.h | 2 + - drivers/video/bcm2708_fb.c | 273 ++++++++++++++++++++++++++++++- + drivers/video/fbdev/bcm2708_fb.c | 273 ++++++++++++++++++++++++++++++- 3 files changed, 278 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-bcm2708/dma.c b/arch/arm/mach-bcm2708/dma.c @@ -94316,10 +92570,10 @@ index ac7a4a0..6d2f9a0 100644 extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base); /* When listing features we can ask for when allocating DMA channels give -diff --git a/drivers/video/bcm2708_fb.c b/drivers/video/bcm2708_fb.c +diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c index 54cd760..798eb52 100644 ---- a/drivers/video/bcm2708_fb.c -+++ b/drivers/video/bcm2708_fb.c +--- a/drivers/video/fbdev/bcm2708_fb.c ++++ b/drivers/video/fbdev/bcm2708_fb.c @@ -21,13 +21,16 @@ #include #include @@ -94695,11 +92949,161 @@ index 54cd760..798eb52 100644 1.9.3 -From 1e7e1f04d02471d6a2c7f0f077d48cbbdf0c2732 Mon Sep 17 00:00:00 2001 -From: Mike Bradley -Date: Mon, 17 Jun 2013 11:31:42 -0700 -Subject: [PATCH 036/124] dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock - held in completion handler +From 7ba7c386c71c076422e25dcbebfa5fc78cc537ad Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 18 Dec 2013 22:16:19 +0000 +Subject: [PATCH 27/53] config: Enable CONFIG_MEMCG, but leave it disabled (due + to memory cost). Enable with cgroup_enable=memory. + +--- + arch/arm/configs/bcmrpi_defconfig | 1 + + kernel/cgroup.c | 23 +++++++++++++++++++++++ + mm/memcontrol.c | 1 + + 3 files changed, 25 insertions(+) + +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 78d789c..e89e430 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -18,6 +18,7 @@ CONFIG_CGROUP_FREEZER=y + CONFIG_CGROUP_DEVICE=y + CONFIG_CGROUP_CPUACCT=y + CONFIG_RESOURCE_COUNTERS=y ++CONFIG_MEMCG=y + CONFIG_BLK_CGROUP=y + CONFIG_NAMESPACES=y + CONFIG_SCHED_AUTOGROUP=y +diff --git a/kernel/cgroup.c b/kernel/cgroup.c +index ceee0c5..39a172b 100644 +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -4620,6 +4620,29 @@ static int __init cgroup_disable(char *str) + } + __setup("cgroup_disable=", cgroup_disable); + ++static int __init cgroup_enable(char *str) ++{ ++ struct cgroup_subsys *ss; ++ char *token; ++ int i; ++ ++ while ((token = strsep(&str, ",")) != NULL) { ++ if (!*token) ++ continue; ++ ++ for_each_subsys(ss, i) { ++ if (!strcmp(token, ss->name)) { ++ ss->disabled = 0; ++ printk(KERN_INFO "Enabling %s control group" ++ " subsystem\n", ss->name); ++ break; ++ } ++ } ++ } ++ return 1; ++} ++__setup("cgroup_enable=", cgroup_enable); ++ + /** + * css_tryget_from_dir - get corresponding css from the dentry of a cgroup dir + * @dentry: directory dentry of interest +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index 5177c6d..4046101 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -7157,6 +7157,7 @@ struct cgroup_subsys memory_cgrp_subsys = { + .bind = mem_cgroup_bind, + .base_cftypes = mem_cgroup_files, + .early_init = 0, ++ .disabled = 1, + }; + + #ifdef CONFIG_MEMCG_SWAP +-- +1.9.3 + + +From ab265aa593f961b282b0be33b3eacd8aaf7c3e0b Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 3 Jul 2013 00:46:42 +0100 +Subject: [PATCH 28/53] Add FIQ patch to dwc_otg driver. Enable with + dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance. Thanks + to Gordon and Costas + +Avoid dynamic memory allocation for channel lock in USB driver. Thanks ddv2005. + +Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh + +Make sure we wait for the reset to finish + +dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent kernel + memory corruption, escalating to OOPS under high USB load. + +dwc_otg: Fix unsafe access of QTD during URB enqueue + +In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the +transaction could complete almost immediately after the qtd was assigned +to a host channel during URB enqueue, which meant the qtd pointer was no +longer valid having been completed and removed. Usually, this resulted in +an OOPS during URB submission. By predetermining whether transactions +need to be queued or not, this unsafe pointer access is avoided. + +This bug was only evident on the Pi model A where a device was attached +that had no periodic endpoints (e.g. USB pendrive or some wlan devices). + +dwc_otg: Fix incorrect URB allocation error handling + +If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS +because for some reason a member of the *unallocated* struct was set to +zero. Error handling changed to fail correctly. + +dwc_otg: fix potential use-after-free case in interrupt handler + +If a transaction had previously aborted, certain interrupts are +enabled to track error counts and reset where necessary. On IN +endpoints the host generates an ACK interrupt near-simultaneously +with completion of transfer. In the case where this transfer had +previously had an error, this results in a use-after-free on +the QTD memory space with a 1-byte length being overwritten to +0x00. + +dwc_otg: add handling of SPLIT transaction data toggle errors + +Previously a data toggle error on packets from a USB1.1 device behind +a TT would result in the Pi locking up as the driver never handled +the associated interrupt. Patch adds basic retry mechanism and +interrupt acknowledgement to cater for either a chance toggle error or +for devices that have a broken initial toggle state (FT8U232/FT232BM). + +dwc_otg: implement tasklet for returning URBs to usbcore hcd layer + +The dwc_otg driver interrupt handler for transfer completion will spend +a very long time with interrupts disabled when a URB is completed - +this is because usb_hcd_giveback_urb is called from within the handler +which for a USB device driver with complicated processing (e.g. webcam) +will take an exorbitant amount of time to complete. This results in +missed completion interrupts for other USB packets which lead to them +being dropped due to microframe overruns. + +This patch splits returning the URB to the usb hcd layer into a +high-priority tasklet. This will have most benefit for isochronous IN +transfers but will also have incidental benefit where multiple periodic +devices are active at once. + +dwc_otg: fix NAK holdoff and allow on split transactions only + +This corrects a bug where if a single active non-periodic endpoint +had at least one transaction in its qh, on frnum == MAX_FRNUM the qh +would get skipped and never get queued again. This would result in +a silent device until error detection (automatic or otherwise) would +either reset the device or flush and requeue the URBs. + +Additionally the NAK holdoff was enabled for all transactions - this +would potentially stall a HS endpoint for 1ms if a previous error state +enabled this interrupt and the next response was a NAK. Fix so that +only split transactions get held off. + +dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock held in completion handler usb_hcd_unlink_urb_from_ep must be called with the HCD lock held. Calling it asynchronously in the tasklet was not safe (regression in @@ -94714,103 +93118,536 @@ when a USB device was unplugged/replugged during data transfer. This effect was reproduced using automated USB port power control, hundreds of replug events were performed during active transfers to confirm that the problem was eliminated. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 2 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 18 ++++++++++++++---- - 2 files changed, 15 insertions(+), 5 deletions(-) -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 73f7643..fe03c43 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -704,6 +704,7 @@ static void completion_tasklet_func(void *ptr) - urb_tq_entry_t *item; - dwc_irqflags_t flags; - -+ /* This could just be spin_lock_irq */ - DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); - while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) { - item = DWC_TAILQ_FIRST(&hcd->completed_urb_list); -@@ -713,7 +714,6 @@ static void completion_tasklet_func(void *ptr) - DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); - DWC_FREE(item); - -- usb_hcd_unlink_urb_from_ep(hcd->priv, urb); - usb_hcd_giveback_urb(hcd->priv, urb, urb->status); - - DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index 39787e3..5e6a26a 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -265,13 +265,15 @@ static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw, - - /** - * Sets the final status of an URB and returns it to the device driver. Any -- * required cleanup of the URB is performed. -+ * required cleanup of the URB is performed. The HCD lock should be held on -+ * entry. - */ - static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, - dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status) - { - struct urb *urb = (struct urb *)urb_handle; - urb_tq_entry_t *new_entry; -+ int rc = 0; - if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { - DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n", - __func__, urb, usb_pipedevice(urb->pipe), -@@ -363,9 +365,17 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, - #endif - } else { - new_entry->urb = urb; -- DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry, -- urb_tq_entries); -- DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet); -+#if USB_URB_EP_LINKING -+ rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); -+ if(0 == rc) { -+ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); -+ } -+#endif -+ if(0 == rc) { -+ DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry, -+ urb_tq_entries); -+ DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet); -+ } - } - return 0; - } --- -1.9.3 - - -From 0a974b6f5ad5c976581582de750861bb121f2017 Mon Sep 17 00:00:00 2001 -From: Gordon Hollingworth -Date: Thu, 4 Apr 2013 11:05:21 +0100 -Subject: [PATCH 037/124] USB fix using a FIQ to implement split transactions +USB fix using a FIQ to implement split transactions This commit adds a FIQ implementaion that schedules the split transactions using a FIQ so we don't get held off by the interrupt latency of Linux ---- - .../usb/host/dwc_common_port/dwc_common_linux.c | 5 + - drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 37 +- - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 6 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 125 ++++- - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 20 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 538 ++++++++++++++++++--- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 18 +- - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 31 +- - drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h | 24 +- - drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 2 +- - 10 files changed, 694 insertions(+), 112 deletions(-) +dwc_otg: fix device attributes and avoid kernel warnings on boot + +dcw_otg: avoid logging function that can cause panics + +See: https://github.com/raspberrypi/firmware/issues/21 +Thanks to cleverca22 for fix + +dwc_otg: mask correct interrupts after transaction error recovery + +The dwc_otg driver will unmask certain interrupts on a transaction +that previously halted in the error state in order to reset the +QTD error count. The various fine-grained interrupt handlers do not +consider that other interrupts besides themselves were unmasked. + +By disabling the two other interrupts only ever enabled in DMA mode +for this purpose, we can avoid unnecessary function calls in the +IRQ handler. This will also prevent an unneccesary FIQ interrupt +from being generated if the FIQ is enabled. + +dwc_otg: fiq: prevent FIQ thrash and incorrect state passing to IRQ + +In the case of a transaction to a device that had previously aborted +due to an error, several interrupts are enabled to reset the error +count when a device responds. This has the side-effect of making the +FIQ thrash because the hardware will generate multiple instances of +a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK +on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the +associated interrupts. + +Additionally, on non-split transactions make sure that only unmasked +interrupts are cleared. This caused a hard-to-trigger but serious +race condition when you had the combination of an endpoint awaiting +error recovery and a transaction completed on an endpoint - due to +the sequencing and timing of interrupts generated by the dwc_otg core, +it was possible to confuse the IRQ handler. + +Fix function tracing + +dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue + +dwc_otg: prevent OOPSes during device disconnects + +The dwc_otg_urb_enqueue function is thread-unsafe. In particular the +access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and +friends does not occur within a critical section and so if a device +was unplugged during activity there was a high chance that the +usbcore hub_thread would try to disable the endpoint with partially- +formed entries in the URB queue. This would result in BUG() or null +pointer dereferences. + +Fix so that access of urb->hcpriv, enqueuing to the hardware and +adding to usbcore endpoint URB lists is contained within a single +critical section. + +dwc_otg: prevent BUG() in TT allocation if hub address is > 16 + +A fixed-size array is used to track TT allocation. This was +previously set to 16 which caused a crash because +dwc_otg_hcd_allocate_port would read past the end of the array. + +This was hit if a hub was plugged in which enumerated as addr > 16, +due to previous device resets or unplugs. + +Also add #ifdef FIQ_DEBUG around hcd->hub_port_alloc[], which grows +to a large size if 128 hub addresses are supported. This field is +for debug only for tracking which frame an allocate happened in. + +dwc_otg: make channel halts with unknown state less damaging + +If the IRQ received a channel halt interrupt through the FIQ +with no other bits set, the IRQ would not release the host +channel and never complete the URB. + +Add catchall handling to treat as a transaction error and retry. + +dwc_otg: fiq_split: use TTs with more granularity + +This fixes certain issues with split transaction scheduling. + +- Isochronous multi-packet OUT transactions now hog the TT until + they are completed - this prevents hubs aborting transactions + if they get a periodic start-split out-of-order +- Don't perform TT allocation on non-periodic endpoints - this + allows simultaneous use of the TT's bulk/control and periodic + transaction buffers + +This commit will mainly affect USB audio playback. + +dwc_otg: fix potential sleep while atomic during urb enqueue + +Fixes a regression introduced with eb1b482a. Kmalloc called from +dwc_otg_hcd_qtd_add / dwc_otg_hcd_qtd_create did not always have +the GPF_ATOMIC flag set. Force this flag when inside the larger +critical section. + +dwc_otg: make fiq_split_enable imply fiq_fix_enable + +Failing to set up the FIQ correctly would result in +"IRQ 32: nobody cared" errors in dmesg. + +dwc_otg: prevent crashes on host port disconnects + +Fix several issues resulting in crashes or inconsistent state +if a Model A root port was disconnected. + +- Clean up queue heads properly in kill_urbs_in_qh_list by + removing the empty QHs from the schedule lists +- Set the halt status properly to prevent IRQ handlers from + using freed memory +- Add fiq_split related cleanup for saved registers +- Make microframe scheduling reclaim host channels if + active during a disconnect +- Abort URBs with -ESHUTDOWN status response, informing + device drivers so they respond in a more correct fashion + and don't try to resubmit URBs +- Prevent IRQ handlers from attempting to handle channel + interrupts if the associated URB was dequeued (and the + driver state was cleared) + +dwc_otg: prevent leaking URBs during enqueue + +A dwc_otg_urb would get leaked if the HCD enqueue function +failed for any reason. Free the URB at the appropriate points. + +dwc_otg: Enable NAK holdoff for control split transactions + +Certain low-speed devices take a very long time to complete a +data or status stage of a control transaction, producing NAK +responses until they complete internal processing - the USB2.0 +spec limit is up to 500mS. This causes the same type of interrupt +storm as seen with USB-serial dongles prior to c8edb238. + +In certain circumstances, usually while booting, this interrupt +storm could cause SD card timeouts. + +dwc_otg: Fix for occasional lockup on boot when doing a USB reset + +dwc_otg: Don't issue traffic to LS devices in FS mode + +Issuing low-speed packets when the root port is in full-speed mode +causes the root port to stop responding. Explicitly fail when +enqueuing URBs to a LS endpoint on a FS bus. + +Fix ARM architecture issue with local_irq_restore() + +If local_fiq_enable() is called before a local_irq_restore(flags) where +the flags variable has the F bit set, the FIQ will be erroneously disabled. + +Fixup arch_local_irq_restore to avoid trampling the F bit in CPSR. + +Also fix some of the hacks previously implemented for previous dwc_otg +incarnations. +--- + arch/arm/Kconfig | 1 + + arch/arm/include/asm/irqflags.h | 16 +- + arch/arm/kernel/fiqasm.S | 4 + + arch/arm/mach-bcm2708/armctrl.c | 19 +- + arch/arm/mach-bcm2708/bcm2708.c | 29 +- + arch/arm/mach-bcm2708/include/mach/irqs.h | 155 ++--- + arch/arm/mach-bcm2708/include/mach/platform.h | 2 + + .../usb/host/dwc_common_port/dwc_common_linux.c | 11 + + drivers/usb/host/dwc_common_port/dwc_list.h | 14 +- + drivers/usb/host/dwc_common_port/dwc_os.h | 2 + + drivers/usb/host/dwc_otg/Makefile | 1 + + drivers/usb/host/dwc_otg/dwc_otg_attr.c | 14 +- + drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 47 +- + drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 1 + + drivers/usb/host/dwc_otg/dwc_otg_driver.c | 52 +- + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 304 +++++++-- + drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 37 +- + drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 3 +- + drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 5 + + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 705 ++++++++++++++++++++- + drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 159 +++-- + drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 53 +- + drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c | 113 ++++ + drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h | 48 ++ + drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 3 + + drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 2 +- + 26 files changed, 1548 insertions(+), 252 deletions(-) + create mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c + create mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index 4b43550..2719812 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -398,6 +398,7 @@ config ARCH_BCM2708 + select ARM_ERRATA_411920 + select MACH_BCM2708 + select VC4 ++ select FIQ + help + This enables support for Broadcom BCM2708 boards. + +diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h +index 3b763d6..5770408 100644 +--- a/arch/arm/include/asm/irqflags.h ++++ b/arch/arm/include/asm/irqflags.h +@@ -145,12 +145,22 @@ static inline unsigned long arch_local_save_flags(void) + } + + /* +- * restore saved IRQ & FIQ state ++ * restore saved IRQ state + */ + static inline void arch_local_irq_restore(unsigned long flags) + { +- asm volatile( +- " msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore" ++ unsigned long temp = 0; ++ flags &= ~(1 << 6); ++ asm volatile ( ++ " mrs %0, cpsr" ++ : "=r" (temp) ++ : ++ : "memory", "cc"); ++ /* Preserve FIQ bit */ ++ temp &= (1 << 6); ++ flags = flags | temp; ++ asm volatile ( ++ " msr cpsr_c, %0 @ local_irq_restore" + : + : "r" (flags) + : "memory", "cc"); +diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S +index 207f9d6..5233d54 100644 +--- a/arch/arm/kernel/fiqasm.S ++++ b/arch/arm/kernel/fiqasm.S +@@ -47,3 +47,7 @@ ENTRY(__get_fiq_regs) + mov r0, r0 @ avoid hazard prior to ARMv4 + mov pc, lr + ENDPROC(__get_fiq_regs) ++ ++ENTRY(__FIQ_Branch) ++ mov pc, r8 ++ENDPROC(__FIQ_Branch) +diff --git a/arch/arm/mach-bcm2708/armctrl.c b/arch/arm/mach-bcm2708/armctrl.c +index da18725..274aa30 100644 +--- a/arch/arm/mach-bcm2708/armctrl.c ++++ b/arch/arm/mach-bcm2708/armctrl.c +@@ -52,8 +52,12 @@ static void armctrl_mask_irq(struct irq_data *d) + 0 + }; + +- unsigned int data = (unsigned int)irq_get_chip_data(d->irq); +- writel(1 << (data & 0x1f), __io_address(disables[(data >> 5) & 0x3])); ++ if (d->irq >= FIQ_START) { ++ writel(0, __io_address(ARM_IRQ_FAST)); ++ } else { ++ unsigned int data = (unsigned int)irq_get_chip_data(d->irq); ++ writel(1 << (data & 0x1f), __io_address(disables[(data >> 5) & 0x3])); ++ } + } + + static void armctrl_unmask_irq(struct irq_data *d) +@@ -65,8 +69,14 @@ static void armctrl_unmask_irq(struct irq_data *d) + 0 + }; + +- unsigned int data = (unsigned int)irq_get_chip_data(d->irq); +- writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3])); ++ if (d->irq >= FIQ_START) { ++ unsigned int data = ++ (unsigned int)irq_get_chip_data(d->irq) - FIQ_START; ++ writel(0x80 | data, __io_address(ARM_IRQ_FAST)); ++ } else { ++ unsigned int data = (unsigned int)irq_get_chip_data(d->irq); ++ writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3])); ++ } + } + + #if defined(CONFIG_PM) +@@ -204,5 +214,6 @@ int __init armctrl_init(void __iomem * base, unsigned int irq_start, + } + + armctrl_pm_register(base, irq_start, resume_sources); ++ init_FIQ(FIQ_START); + return 0; + } +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index c8763c9..320b5d2 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -321,12 +321,32 @@ static struct resource bcm2708_usb_resources[] = { + .flags = IORESOURCE_MEM, + }, + [1] = { +- .start = IRQ_USB, +- .end = IRQ_USB, ++ .start = MPHI_BASE, ++ .end = MPHI_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = IRQ_HOSTPORT, ++ .end = IRQ_HOSTPORT, + .flags = IORESOURCE_IRQ, + }, + }; + ++bool fiq_fix_enable = true; ++ ++static struct resource bcm2708_usb_resources_no_fiq_fix[] = { ++ [0] = { ++ .start = USB_BASE, ++ .end = USB_BASE + SZ_128K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_USB, ++ .end = IRQ_USB, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ + static u64 usb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); + + static struct platform_device bcm2708_usb_device = { +@@ -709,6 +729,11 @@ void __init bcm2708_init(void) + #endif + bcm_register_device(&bcm2708_systemtimer_device); + bcm_register_device(&bcm2708_fb_device); ++ if (!fiq_fix_enable) ++ { ++ bcm2708_usb_device.resource = bcm2708_usb_resources_no_fiq_fix; ++ bcm2708_usb_device.num_resources = ARRAY_SIZE(bcm2708_usb_resources_no_fiq_fix); ++ } + bcm_register_device(&bcm2708_usb_device); + bcm_register_device(&bcm2708_uart1_device); + bcm_register_device(&bcm2708_powerman_device); +diff --git a/arch/arm/mach-bcm2708/include/mach/irqs.h b/arch/arm/mach-bcm2708/include/mach/irqs.h +index faf5d1a..4299054 100644 +--- a/arch/arm/mach-bcm2708/include/mach/irqs.h ++++ b/arch/arm/mach-bcm2708/include/mach/irqs.h +@@ -106,89 +106,92 @@ + #define IRQ_PENDING1 (IRQ_ARMCTRL_START + INTERRUPT_PENDING1) + #define IRQ_PENDING2 (IRQ_ARMCTRL_START + INTERRUPT_PENDING2) + ++#define FIQ_START HARD_IRQS ++ + /* + * FIQ interrupts definitions are the same as the INT definitions. + */ +-#define FIQ_TIMER0 INT_TIMER0 +-#define FIQ_TIMER1 INT_TIMER1 +-#define FIQ_TIMER2 INT_TIMER2 +-#define FIQ_TIMER3 INT_TIMER3 +-#define FIQ_CODEC0 INT_CODEC0 +-#define FIQ_CODEC1 INT_CODEC1 +-#define FIQ_CODEC2 INT_CODEC2 +-#define FIQ_JPEG INT_JPEG +-#define FIQ_ISP INT_ISP +-#define FIQ_USB INT_USB +-#define FIQ_3D INT_3D +-#define FIQ_TRANSPOSER INT_TRANSPOSER +-#define FIQ_MULTICORESYNC0 INT_MULTICORESYNC0 +-#define FIQ_MULTICORESYNC1 INT_MULTICORESYNC1 +-#define FIQ_MULTICORESYNC2 INT_MULTICORESYNC2 +-#define FIQ_MULTICORESYNC3 INT_MULTICORESYNC3 +-#define FIQ_DMA0 INT_DMA0 +-#define FIQ_DMA1 INT_DMA1 +-#define FIQ_DMA2 INT_DMA2 +-#define FIQ_DMA3 INT_DMA3 +-#define FIQ_DMA4 INT_DMA4 +-#define FIQ_DMA5 INT_DMA5 +-#define FIQ_DMA6 INT_DMA6 +-#define FIQ_DMA7 INT_DMA7 +-#define FIQ_DMA8 INT_DMA8 +-#define FIQ_DMA9 INT_DMA9 +-#define FIQ_DMA10 INT_DMA10 +-#define FIQ_DMA11 INT_DMA11 +-#define FIQ_DMA12 INT_DMA12 +-#define FIQ_AUX INT_AUX +-#define FIQ_ARM INT_ARM +-#define FIQ_VPUDMA INT_VPUDMA +-#define FIQ_HOSTPORT INT_HOSTPORT +-#define FIQ_VIDEOSCALER INT_VIDEOSCALER +-#define FIQ_CCP2TX INT_CCP2TX +-#define FIQ_SDC INT_SDC +-#define FIQ_DSI0 INT_DSI0 +-#define FIQ_AVE INT_AVE +-#define FIQ_CAM0 INT_CAM0 +-#define FIQ_CAM1 INT_CAM1 +-#define FIQ_HDMI0 INT_HDMI0 +-#define FIQ_HDMI1 INT_HDMI1 +-#define FIQ_PIXELVALVE1 INT_PIXELVALVE1 +-#define FIQ_I2CSPISLV INT_I2CSPISLV +-#define FIQ_DSI1 INT_DSI1 +-#define FIQ_PWA0 INT_PWA0 +-#define FIQ_PWA1 INT_PWA1 +-#define FIQ_CPR INT_CPR +-#define FIQ_SMI INT_SMI +-#define FIQ_GPIO0 INT_GPIO0 +-#define FIQ_GPIO1 INT_GPIO1 +-#define FIQ_GPIO2 INT_GPIO2 +-#define FIQ_GPIO3 INT_GPIO3 +-#define FIQ_I2C INT_I2C +-#define FIQ_SPI INT_SPI +-#define FIQ_I2SPCM INT_I2SPCM +-#define FIQ_SDIO INT_SDIO +-#define FIQ_UART INT_UART +-#define FIQ_SLIMBUS INT_SLIMBUS +-#define FIQ_VEC INT_VEC +-#define FIQ_CPG INT_CPG +-#define FIQ_RNG INT_RNG +-#define FIQ_ARASANSDIO INT_ARASANSDIO +-#define FIQ_AVSPMON INT_AVSPMON ++#define FIQ_TIMER0 (FIQ_START+INTERRUPT_TIMER0) ++#define FIQ_TIMER1 (FIQ_START+INTERRUPT_TIMER1) ++#define FIQ_TIMER2 (FIQ_START+INTERRUPT_TIMER2) ++#define FIQ_TIMER3 (FIQ_START+INTERRUPT_TIMER3) ++#define FIQ_CODEC0 (FIQ_START+INTERRUPT_CODEC0) ++#define FIQ_CODEC1 (FIQ_START+INTERRUPT_CODEC1) ++#define FIQ_CODEC2 (FIQ_START+INTERRUPT_CODEC2) ++#define FIQ_JPEG (FIQ_START+INTERRUPT_JPEG) ++#define FIQ_ISP (FIQ_START+INTERRUPT_ISP) ++#define FIQ_USB (FIQ_START+INTERRUPT_USB) ++#define FIQ_3D (FIQ_START+INTERRUPT_3D) ++#define FIQ_TRANSPOSER (FIQ_START+INTERRUPT_TRANSPOSER) ++#define FIQ_MULTICORESYNC0 (FIQ_START+INTERRUPT_MULTICORESYNC0) ++#define FIQ_MULTICORESYNC1 (FIQ_START+INTERRUPT_MULTICORESYNC1) ++#define FIQ_MULTICORESYNC2 (FIQ_START+INTERRUPT_MULTICORESYNC2) ++#define FIQ_MULTICORESYNC3 (FIQ_START+INTERRUPT_MULTICORESYNC3) ++#define FIQ_DMA0 (FIQ_START+INTERRUPT_DMA0) ++#define FIQ_DMA1 (FIQ_START+INTERRUPT_DMA1) ++#define FIQ_DMA2 (FIQ_START+INTERRUPT_DMA2) ++#define FIQ_DMA3 (FIQ_START+INTERRUPT_DMA3) ++#define FIQ_DMA4 (FIQ_START+INTERRUPT_DMA4) ++#define FIQ_DMA5 (FIQ_START+INTERRUPT_DMA5) ++#define FIQ_DMA6 (FIQ_START+INTERRUPT_DMA6) ++#define FIQ_DMA7 (FIQ_START+INTERRUPT_DMA7) ++#define FIQ_DMA8 (FIQ_START+INTERRUPT_DMA8) ++#define FIQ_DMA9 (FIQ_START+INTERRUPT_DMA9) ++#define FIQ_DMA10 (FIQ_START+INTERRUPT_DMA10) ++#define FIQ_DMA11 (FIQ_START+INTERRUPT_DMA11) ++#define FIQ_DMA12 (FIQ_START+INTERRUPT_DMA12) ++#define FIQ_AUX (FIQ_START+INTERRUPT_AUX) ++#define FIQ_ARM (FIQ_START+INTERRUPT_ARM) ++#define FIQ_VPUDMA (FIQ_START+INTERRUPT_VPUDMA) ++#define FIQ_HOSTPORT (FIQ_START+INTERRUPT_HOSTPORT) ++#define FIQ_VIDEOSCALER (FIQ_START+INTERRUPT_VIDEOSCALER) ++#define FIQ_CCP2TX (FIQ_START+INTERRUPT_CCP2TX) ++#define FIQ_SDC (FIQ_START+INTERRUPT_SDC) ++#define FIQ_DSI0 (FIQ_START+INTERRUPT_DSI0) ++#define FIQ_AVE (FIQ_START+INTERRUPT_AVE) ++#define FIQ_CAM0 (FIQ_START+INTERRUPT_CAM0) ++#define FIQ_CAM1 (FIQ_START+INTERRUPT_CAM1) ++#define FIQ_HDMI0 (FIQ_START+INTERRUPT_HDMI0) ++#define FIQ_HDMI1 (FIQ_START+INTERRUPT_HDMI1) ++#define FIQ_PIXELVALVE1 (FIQ_START+INTERRUPT_PIXELVALVE1) ++#define FIQ_I2CSPISLV (FIQ_START+INTERRUPT_I2CSPISLV) ++#define FIQ_DSI1 (FIQ_START+INTERRUPT_DSI1) ++#define FIQ_PWA0 (FIQ_START+INTERRUPT_PWA0) ++#define FIQ_PWA1 (FIQ_START+INTERRUPT_PWA1) ++#define FIQ_CPR (FIQ_START+INTERRUPT_CPR) ++#define FIQ_SMI (FIQ_START+INTERRUPT_SMI) ++#define FIQ_GPIO0 (FIQ_START+INTERRUPT_GPIO0) ++#define FIQ_GPIO1 (FIQ_START+INTERRUPT_GPIO1) ++#define FIQ_GPIO2 (FIQ_START+INTERRUPT_GPIO2) ++#define FIQ_GPIO3 (FIQ_START+INTERRUPT_GPIO3) ++#define FIQ_I2C (FIQ_START+INTERRUPT_I2C) ++#define FIQ_SPI (FIQ_START+INTERRUPT_SPI) ++#define FIQ_I2SPCM (FIQ_START+INTERRUPT_I2SPCM) ++#define FIQ_SDIO (FIQ_START+INTERRUPT_SDIO) ++#define FIQ_UART (FIQ_START+INTERRUPT_UART) ++#define FIQ_SLIMBUS (FIQ_START+INTERRUPT_SLIMBUS) ++#define FIQ_VEC (FIQ_START+INTERRUPT_VEC) ++#define FIQ_CPG (FIQ_START+INTERRUPT_CPG) ++#define FIQ_RNG (FIQ_START+INTERRUPT_RNG) ++#define FIQ_ARASANSDIO (FIQ_START+INTERRUPT_ARASANSDIO) ++#define FIQ_AVSPMON (FIQ_START+INTERRUPT_AVSPMON) + +-#define FIQ_ARM_TIMER INT_ARM_TIMER +-#define FIQ_ARM_MAILBOX INT_ARM_MAILBOX +-#define FIQ_ARM_DOORBELL_0 INT_ARM_DOORBELL_0 +-#define FIQ_ARM_DOORBELL_1 INT_ARM_DOORBELL_1 +-#define FIQ_VPU0_HALTED INT_VPU0_HALTED +-#define FIQ_VPU1_HALTED INT_VPU1_HALTED +-#define FIQ_ILLEGAL_TYPE0 INT_ILLEGAL_TYPE0 +-#define FIQ_ILLEGAL_TYPE1 INT_ILLEGAL_TYPE1 +-#define FIQ_PENDING1 INT_PENDING1 +-#define FIQ_PENDING2 INT_PENDING2 ++#define FIQ_ARM_TIMER (FIQ_START+INTERRUPT_ARM_TIMER) ++#define FIQ_ARM_MAILBOX (FIQ_START+INTERRUPT_ARM_MAILBOX) ++#define FIQ_ARM_DOORBELL_0 (FIQ_START+INTERRUPT_ARM_DOORBELL_0) ++#define FIQ_ARM_DOORBELL_1 (FIQ_START+INTERRUPT_ARM_DOORBELL_1) ++#define FIQ_VPU0_HALTED (FIQ_START+INTERRUPT_VPU0_HALTED) ++#define FIQ_VPU1_HALTED (FIQ_START+INTERRUPT_VPU1_HALTED) ++#define FIQ_ILLEGAL_TYPE0 (FIQ_START+INTERRUPT_ILLEGAL_TYPE0) ++#define FIQ_ILLEGAL_TYPE1 (FIQ_START+INTERRUPT_ILLEGAL_TYPE1) ++#define FIQ_PENDING1 (FIQ_START+INTERRUPT_PENDING1) ++#define FIQ_PENDING2 (FIQ_START+INTERRUPT_PENDING2) + + #define HARD_IRQS (64 + 21) +-#define GPIO_IRQ_START (HARD_IRQS) ++#define FIQ_IRQS (64 + 21) ++#define GPIO_IRQ_START (HARD_IRQS + FIQ_IRQS) + #define GPIO_IRQS (32*5) + #define SPARE_IRQS (64) +-#define NR_IRQS (HARD_IRQS+GPIO_IRQS+SPARE_IRQS) ++#define NR_IRQS (HARD_IRQS+FIQ_IRQS+GPIO_IRQS+SPARE_IRQS) + + #endif /* _BCM2708_IRQS_H_ */ +diff --git a/arch/arm/mach-bcm2708/include/mach/platform.h b/arch/arm/mach-bcm2708/include/mach/platform.h +index f4bb733..992a630 100644 +--- a/arch/arm/mach-bcm2708/include/mach/platform.h ++++ b/arch/arm/mach-bcm2708/include/mach/platform.h +@@ -56,7 +56,9 @@ + */ + + #define BCM2708_PERI_BASE 0x20000000 ++#define IC0_BASE (BCM2708_PERI_BASE + 0x2000) + #define ST_BASE (BCM2708_PERI_BASE + 0x3000) /* System Timer */ ++#define MPHI_BASE (BCM2708_PERI_BASE + 0x6000) /* Message -based Parallel Host Interface */ + #define DMA_BASE (BCM2708_PERI_BASE + 0x7000) /* DMA controller */ + #define ARM_BASE (BCM2708_PERI_BASE + 0xB000) /* BCM2708 ARM control block */ + #define PM_BASE (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */ diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -index 1788812..0812d3a 100644 +index 440bcfc..6d01261 100644 --- a/drivers/usb/host/dwc_common_port/dwc_common_linux.c +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -@@ -580,7 +580,12 @@ void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value) +@@ -580,7 +580,13 @@ void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value) void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask) { @@ -94819,24 +93656,154 @@ index 1788812..0812d3a 100644 + local_irq_save(flags); + local_fiq_disable(); writel((readl(reg) & ~clear_mask) | set_mask, reg); ++ local_fiq_enable(); + local_irq_restore(flags); } #if 0 +@@ -991,6 +997,11 @@ void DWC_TASK_SCHEDULE(dwc_tasklet_t *task) + tasklet_schedule(&task->t); + } + ++void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task) ++{ ++ tasklet_hi_schedule(&task->t); ++} ++ + + /* workqueues + - run in process context (can sleep) +diff --git a/drivers/usb/host/dwc_common_port/dwc_list.h b/drivers/usb/host/dwc_common_port/dwc_list.h +index 89cc325..4ce560d 100644 +--- a/drivers/usb/host/dwc_common_port/dwc_list.h ++++ b/drivers/usb/host/dwc_common_port/dwc_list.h +@@ -384,17 +384,17 @@ struct { \ + #define DWC_TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + #define DWC_TAILQ_EMPTY(head) \ +- (TAILQ_FIRST(head) == TAILQ_END(head)) ++ (DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head)) + + #define DWC_TAILQ_FOREACH(var, head, field) \ +- for((var) = TAILQ_FIRST(head); \ +- (var) != TAILQ_END(head); \ +- (var) = TAILQ_NEXT(var, field)) ++ for ((var) = DWC_TAILQ_FIRST(head); \ ++ (var) != DWC_TAILQ_END(head); \ ++ (var) = DWC_TAILQ_NEXT(var, field)) + + #define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \ +- for((var) = TAILQ_LAST(head, headname); \ +- (var) != TAILQ_END(head); \ +- (var) = TAILQ_PREV(var, headname, field)) ++ for ((var) = DWC_TAILQ_LAST(head, headname); \ ++ (var) != DWC_TAILQ_END(head); \ ++ (var) = DWC_TAILQ_PREV(var, headname, field)) + + /* + * Tail queue functions. +diff --git a/drivers/usb/host/dwc_common_port/dwc_os.h b/drivers/usb/host/dwc_common_port/dwc_os.h +index 9ffe929..09ed244 100644 +--- a/drivers/usb/host/dwc_common_port/dwc_os.h ++++ b/drivers/usb/host/dwc_common_port/dwc_os.h +@@ -981,6 +981,8 @@ extern void DWC_TASK_FREE(dwc_tasklet_t *task); + extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task); + #define dwc_task_schedule DWC_TASK_SCHEDULE + ++extern void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task); ++#define dwc_task_hi_schedule DWC_TASK_HI_SCHEDULE + + /** @name Timer + * +diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile +index 236c47c..a56f193 100644 +--- a/drivers/usb/host/dwc_otg/Makefile ++++ b/drivers/usb/host/dwc_otg/Makefile +@@ -36,6 +36,7 @@ dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o + dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o + dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o + dwc_otg-objs += dwc_otg_adp.o ++dwc_otg-objs += dwc_otg_mphi_fix.o + ifneq ($(CFI),) + dwc_otg-objs += dwc_otg_cfi.o + endif +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.c b/drivers/usb/host/dwc_otg/dwc_otg_attr.c +index fab2961..9da0c92 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_attr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c +@@ -909,7 +909,7 @@ static ssize_t regdump_show(struct device *_dev, + return sprintf(buf, "Register Dump\n"); + } + +-DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0); ++DEVICE_ATTR(regdump, S_IRUGO, regdump_show, 0); + + /** + * Dump global registers and either host or device registers (depending on the +@@ -920,12 +920,12 @@ static ssize_t spramdump_show(struct device *_dev, + { + dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev); + +- dwc_otg_dump_spram(otg_dev->core_if); ++ //dwc_otg_dump_spram(otg_dev->core_if); + + return sprintf(buf, "SPRAM Dump\n"); + } + +-DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0); ++DEVICE_ATTR(spramdump, S_IRUGO, spramdump_show, 0); + + /** + * Dump the current hcd state. +@@ -940,7 +940,7 @@ static ssize_t hcddump_show(struct device *_dev, + return sprintf(buf, "HCD Dump\n"); + } + +-DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0); ++DEVICE_ATTR(hcddump, S_IRUGO, hcddump_show, 0); + + /** + * Dump the average frame remaining at SOF. This can be used to +@@ -958,7 +958,7 @@ static ssize_t hcd_frrem_show(struct device *_dev, + return sprintf(buf, "HCD Dump Frame Remaining\n"); + } + +-DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0); ++DEVICE_ATTR(hcd_frrem, S_IRUGO, hcd_frrem_show, 0); + + /** + * Displays the time required to read the GNPTXFSIZ register many times (the +@@ -986,7 +986,7 @@ static ssize_t rd_reg_test_show(struct device *_dev, + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); + } + +-DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0); ++DEVICE_ATTR(rd_reg_test, S_IRUGO, rd_reg_test_show, 0); + + /** + * Displays the time required to write the GNPTXFSIZ register many times (the +@@ -1014,7 +1014,7 @@ static ssize_t wr_reg_test_show(struct device *_dev, + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); + } + +-DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0); ++DEVICE_ATTR(wr_reg_test, S_IRUGO, wr_reg_test_show, 0); + + #ifdef CONFIG_USB_DWC_OTG_LPM + diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -index 096a3f1..2f8b3bd 100644 +index 59fc862..2f8b3bd 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -@@ -47,8 +47,6 @@ +@@ -45,6 +45,7 @@ + #include "dwc_otg_driver.h" + #include "dwc_otg_pcd.h" #include "dwc_otg_hcd.h" - #include "dwc_otg_mphi_fix.h" ++#include "dwc_otg_mphi_fix.h" --extern bool fiq_fix_enable; -- #ifdef DEBUG inline const char *op_state_str(dwc_otg_core_if_t * core_if) - { -@@ -1321,7 +1319,7 @@ static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if) +@@ -1318,7 +1319,7 @@ static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if) /** * This function returns the Core Interrupt register. */ @@ -94845,7 +93812,7 @@ index 096a3f1..2f8b3bd 100644 { gahbcfg_data_t gahbcfg = {.d32 = 0 }; gintsts_data_t gintsts; -@@ -1338,19 +1336,33 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if) +@@ -1335,26 +1336,45 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if) gintmsk_common.b.lpmtranrcvd = 1; #endif gintmsk_common.b.restoredone = 1; @@ -94885,7 +93852,22 @@ index 096a3f1..2f8b3bd 100644 gintsts.d32, gintmsk.d32); } #endif -@@ -1394,6 +1406,7 @@ int32_t dwc_otg_handle_common_intr(void *dev) +- if (gahbcfg.b.glblintrmsk) ++ if (!fiq_fix_enable){ ++ if (gahbcfg.b.glblintrmsk) ++ return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); ++ else ++ return 0; ++ } ++ else { + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); +- else +- return 0; ++ } + + } + +@@ -1386,6 +1406,7 @@ int32_t dwc_otg_handle_common_intr(void *dev) { int retval = 0; gintsts_data_t gintsts; @@ -94893,7 +93875,7 @@ index 096a3f1..2f8b3bd 100644 gpwrdn_data_t gpwrdn = {.d32 = 0 }; dwc_otg_device_t *otg_dev = dev; dwc_otg_core_if_t *core_if = otg_dev->core_if; -@@ -1415,7 +1428,7 @@ int32_t dwc_otg_handle_common_intr(void *dev) +@@ -1407,7 +1428,7 @@ int32_t dwc_otg_handle_common_intr(void *dev) } if (core_if->hibernation_suspend <= 0) { @@ -94902,7 +93884,7 @@ index 096a3f1..2f8b3bd 100644 if (gintsts.b.modemismatch) { retval |= dwc_otg_handle_mode_mismatch_intr(core_if); -@@ -1512,8 +1525,12 @@ int32_t dwc_otg_handle_common_intr(void *dev) +@@ -1504,8 +1525,12 @@ int32_t dwc_otg_handle_common_intr(void *dev) gintsts.b.portintr = 1; DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32); retval |= 1; @@ -94915,50 +93897,348 @@ index 096a3f1..2f8b3bd 100644 } else { DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32); +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_dbg.h b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h +index 8900318..ccc24e0 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_dbg.h ++++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h +@@ -49,6 +49,7 @@ static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new) + return old; + } + ++#define DBG_USER (0x1) + /** When debug level has the DBG_CIL bit set, display CIL Debug messages. */ + #define DBG_CIL (0x2) + /** When debug level has the DBG_CILV bit set, display CIL Verbose debug diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index c2bb596..176dc14 100644 +index ac2c846..f06c3d22 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -242,7 +242,8 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { +@@ -64,6 +64,8 @@ bool microframe_schedule=true; - //Global variable to switch the fiq fix on or off (declared in bcm2708.c) - extern bool fiq_fix_enable; -- + static const char dwc_driver_name[] = "dwc_otg"; + ++extern void* dummy_send; ++ + extern int pcd_init( + #ifdef LM_INTERFACE + struct lm_device *_dev +@@ -238,6 +240,14 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { + .adp_enable = -1, + }; + ++//Global variable to switch the fiq fix on or off (declared in bcm2708.c) ++extern bool fiq_fix_enable; +// Global variable to enable the split transaction fix +bool fiq_split_enable = true; - //Global variable to switch the nak holdoff on or off - bool nak_holdoff_enable = true; ++//Global variable to switch the nak holdoff on or off ++bool nak_holdoff_enable = true; ++ ++ + /** + * This function shows the Driver Version. + */ +@@ -779,17 +789,33 @@ static int dwc_otg_driver_probe( + _dev->resource->start, + _dev->resource->end - _dev->resource->start + 1); + #if 1 +- if (!request_mem_region(_dev->resource->start, +- _dev->resource->end - _dev->resource->start + 1, ++ if (!request_mem_region(_dev->resource[0].start, ++ _dev->resource[0].end - _dev->resource[0].start + 1, + "dwc_otg")) { + dev_dbg(&_dev->dev, "error reserving mapped memory\n"); + retval = -EFAULT; + goto fail; + } -@@ -1090,6 +1091,7 @@ static int __init dwc_otg_driver_init(void) +- dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource->start, +- _dev->resource->end - +- _dev->resource->start+1); ++ dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start, ++ _dev->resource[0].end - ++ _dev->resource[0].start+1); ++ if (fiq_fix_enable) ++ { ++ if (!request_mem_region(_dev->resource[1].start, ++ _dev->resource[1].end - _dev->resource[1].start + 1, ++ "dwc_otg")) { ++ dev_dbg(&_dev->dev, "error reserving mapped memory\n"); ++ retval = -EFAULT; ++ goto fail; ++ } ++ ++ dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start, ++ _dev->resource[1].end - ++ _dev->resource[1].start + 1); ++ dummy_send = (void *) kmalloc(16, GFP_ATOMIC); ++ } ++ + #else + { + struct map_desc desc = { +@@ -1044,6 +1070,12 @@ static int __init dwc_otg_driver_init(void) + int retval = 0; + int error; + struct device_driver *drv; ++ ++ if(fiq_split_enable && !fiq_fix_enable) { ++ printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n"); ++ fiq_fix_enable = 1; ++ } ++ + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name, + DWC_DRIVER_VERSION, + #ifdef LM_INTERFACE +@@ -1063,6 +1095,9 @@ static int __init dwc_otg_driver_init(void) + printk(KERN_ERR "%s retval=%d\n", __func__, retval); + return retval; } - printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled"); - printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled"); ++ printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled"); ++ printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled"); + printk(KERN_DEBUG "dwc_otg: FIQ split fix %s\n", fiq_split_enable ? "enabled":"disabled"); error = driver_create_file(drv, &driver_attr_version); #ifdef DEBUG -@@ -1374,6 +1376,8 @@ module_param(fiq_fix_enable, bool, 0444); - MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix"); - module_param(nak_holdoff_enable, bool, 0444); - MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff"); +@@ -1343,6 +1378,13 @@ MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0"); + module_param(microframe_schedule, bool, 0444); + MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler"); + ++module_param(fiq_fix_enable, bool, 0444); ++MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix"); ++module_param(nak_holdoff_enable, bool, 0444); ++MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff"); +module_param(fiq_split_enable, bool, 0444); +MODULE_PARM_DESC(fiq_split_enable, "Enable the FIQ fix on split transactions"); - ++ /** @page "Module Parameters" * + * The following parameters may be specified when starting the module. diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index fe03c43..ec00b13 100644 +index ab935c0..22300f0 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -45,6 +45,7 @@ +@@ -40,10 +40,14 @@ + * header file. + */ ++#include ++#include ++ #include "dwc_otg_hcd.h" #include "dwc_otg_regs.h" +#include "dwc_otg_mphi_fix.h" - extern bool microframe_schedule, nak_holdoff_enable; +-extern bool microframe_schedule; ++extern bool microframe_schedule, nak_holdoff_enable; -@@ -581,6 +582,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, + //#define DEBUG_HOST_CHANNELS + #ifdef DEBUG_HOST_CHANNELS +@@ -53,6 +57,13 @@ static int last_sel_trans_num_avail_hc_at_start = 0; + static int last_sel_trans_num_avail_hc_at_end = 0; + #endif /* DEBUG_HOST_CHANNELS */ + ++extern int g_next_sched_frame, g_np_count, g_np_sent; ++ ++extern haint_data_t haint_saved; ++extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; ++extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; ++extern gintsts_data_t ginsts_saved; ++ + dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) + { + return DWC_ALLOC(sizeof(dwc_otg_hcd_t)); +@@ -162,31 +173,43 @@ static void del_timers(dwc_otg_hcd_t * hcd) + + /** + * Processes all the URBs in a single list of QHs. Completes them with +- * -ETIMEDOUT and frees the QTD. ++ * -ESHUTDOWN and frees the QTD. + */ + static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) + { +- dwc_list_link_t *qh_item; ++ dwc_list_link_t *qh_item, *qh_tmp; + dwc_otg_qh_t *qh; + dwc_otg_qtd_t *qtd, *qtd_tmp; + +- DWC_LIST_FOREACH(qh_item, qh_list) { ++ DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) { + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry); + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, + &qh->qtd_list, qtd_list_entry) { + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); + if (qtd->urb != NULL) { + hcd->fops->complete(hcd, qtd->urb->priv, +- qtd->urb, -DWC_E_TIMEOUT); ++ qtd->urb, -DWC_E_SHUTDOWN); + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); + } + + } ++ if(qh->channel) { ++ /* Using hcchar.chen == 1 is not a reliable test. ++ * It is possible that the channel has already halted ++ * but not yet been through the IRQ handler. ++ */ ++ dwc_otg_hc_halt(hcd->core_if, qh->channel, ++ DWC_OTG_HC_XFER_URB_DEQUEUE); ++ if(microframe_schedule) ++ hcd->available_host_channels++; ++ qh->channel = NULL; ++ } ++ dwc_otg_hcd_qh_remove(hcd, qh); + } + } + + /** +- * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic ++ * Responds with an error status of ESHUTDOWN to all URBs in the non-periodic + * and periodic schedules. The QTD associated with each URB is removed from + * the schedule and freed. This function may be called when a disconnect is + * detected or when the HCD is being stopped. +@@ -272,7 +295,8 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) + */ + dwc_otg_hcd->flags.b.port_connect_status_change = 1; + dwc_otg_hcd->flags.b.port_connect_status = 0; +- ++ if(fiq_fix_enable) ++ local_fiq_disable(); + /* + * Shutdown any transfers in process by clearing the Tx FIFO Empty + * interrupt mask and status bits and disabling subsequent host +@@ -368,8 +392,22 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) + channel->qh = NULL; + } + } ++ if(fiq_split_enable) { ++ for(i=0; i < 128; i++) { ++ dwc_otg_hcd->hub_port[i] = 0; ++ } ++ haint_saved.d32 = 0; ++ for(i=0; i < MAX_EPS_CHANNELS; i++) { ++ hcint_saved[i].d32 = 0; ++ hcintmsk_saved[i].d32 = 0; ++ } ++ } ++ + } + ++ if(fiq_fix_enable) ++ local_fiq_enable(); ++ + if (dwc_otg_hcd->fops->disconnect) { + dwc_otg_hcd->fops->disconnect(dwc_otg_hcd); + } +@@ -407,6 +445,7 @@ static int dwc_otg_hcd_sleep_cb(void *p) + } + #endif + ++ + /** + * HCD Callback function for Remote Wakeup. + * +@@ -457,10 +496,12 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, + dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle, + int atomic_alloc) + { +- dwc_irqflags_t flags; + int retval = 0; ++ uint8_t needs_scheduling = 0; ++ dwc_otg_transaction_type_e tr_type; + dwc_otg_qtd_t *qtd; + gintmsk_data_t intr_mask = {.d32 = 0 }; ++ hprt0_data_t hprt0 = { .d32 = 0 }; + + #ifdef DEBUG /* integrity checks (Broadcom) */ + if (NULL == hcd->core_if) { +@@ -475,6 +516,16 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, + return -DWC_E_NO_DEVICE; + } + ++ /* Some core configurations cannot support LS traffic on a FS root port */ ++ if ((hcd->fops->speed(hcd, dwc_otg_urb->priv) == USB_SPEED_LOW) && ++ (hcd->core_if->hwcfg2.b.fs_phy_type == 1) && ++ (hcd->core_if->hwcfg2.b.hs_phy_type == 1)) { ++ hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0); ++ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED) { ++ return -DWC_E_NO_DEVICE; ++ } ++ } ++ + qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc); + if (qtd == NULL) { + DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n"); +@@ -490,32 +541,27 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, + return -DWC_E_NO_MEMORY; + } + #endif +- retval = +- dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc); ++ intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); ++ if(!intr_mask.b.sofintr) needs_scheduling = 1; ++ if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) ++ /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */ ++ needs_scheduling = 0; ++ ++ retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc); + // creates a new queue in ep_handle if it doesn't exist already + if (retval < 0) { + DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. " + "Error status %d\n", retval); + dwc_otg_hcd_qtd_free(qtd); +- } else { +- qtd->qh = *ep_handle; ++ return retval; + } +- intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); +- if (!intr_mask.b.sofintr && retval == 0) { +- dwc_otg_transaction_type_e tr_type; +- if ((qtd->qh->ep_type == UE_BULK) +- && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) { +- /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */ +- return 0; +- } +- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ ++ if(needs_scheduling) { + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE) { + dwc_otg_hcd_queue_transactions(hcd, tr_type); + } +- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); + } +- + return retval; + } + +@@ -524,6 +570,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, + { + dwc_otg_qh_t *qh; + dwc_otg_qtd_t *urb_qtd; ++ BUG_ON(!hcd); ++ BUG_ON(!dwc_otg_urb); + + #ifdef DEBUG /* integrity checks (Broadcom) */ + +@@ -540,14 +588,17 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, + return -DWC_E_INVALID; + } + urb_qtd = dwc_otg_urb->qtd; ++ BUG_ON(!urb_qtd); + if (urb_qtd->qh == NULL) { + DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n"); + return -DWC_E_INVALID; + } + #else + urb_qtd = dwc_otg_urb->qtd; ++ BUG_ON(!urb_qtd); + #endif + qh = urb_qtd->qh; ++ BUG_ON(!qh); + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { + if (urb_qtd->in_process) { + dump_channel_info(hcd, qh); +@@ -571,6 +622,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, */ dwc_otg_hc_halt(hcd->core_if, qh->channel, DWC_OTG_HC_XFER_URB_DEQUEUE); @@ -94967,27 +94247,96 @@ index fe03c43..ec00b13 100644 } } -@@ -716,6 +719,8 @@ static void completion_tasklet_func(void *ptr) - - usb_hcd_giveback_urb(hcd->priv, urb, urb->status); +@@ -687,6 +740,33 @@ static void reset_tasklet_func(void *data) + dwc_otg_hcd->flags.b.port_reset_change = 1; + } ++static void completion_tasklet_func(void *ptr) ++{ ++ dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr; ++ struct urb *urb; ++ urb_tq_entry_t *item; ++ dwc_irqflags_t flags; ++ ++ /* This could just be spin_lock_irq */ ++ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) { ++ item = DWC_TAILQ_FIRST(&hcd->completed_urb_list); ++ urb = item->urb; ++ DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item, ++ urb_tq_entries); ++ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); ++ DWC_FREE(item); ++ ++ usb_hcd_giveback_urb(hcd->priv, urb, urb->status); ++ + fiq_print(FIQDBG_PORTHUB, "COMPLETE"); + - DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ } ++ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); ++ return; ++} ++ + static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) + { + dwc_list_link_t *item; +@@ -819,12 +899,14 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) + } else if (dwc_otg_hcd->status_buf != NULL) { + DWC_FREE(dwc_otg_hcd->status_buf); } - DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); -@@ -979,6 +984,10 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) ++ DWC_SPINLOCK_FREE(dwc_otg_hcd->channel_lock); + DWC_SPINLOCK_FREE(dwc_otg_hcd->lock); + /* Set core_if's lock pointer to NULL */ + dwc_otg_hcd->core_if->lock = NULL; + + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer); + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet); ++ DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet); + + #ifdef DWC_DEV_SRPCAP + if (dwc_otg_hcd->core_if->power_down == 2 && +@@ -845,6 +927,7 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) + dwc_hc_t *channel; + + hcd->lock = DWC_SPINLOCK_ALLOC(); ++ hcd->channel_lock = DWC_SPINLOCK_ALLOC(); + DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n", + hcd, core_if); + if (!hcd->lock) { +@@ -868,7 +951,7 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) + DWC_LIST_INIT(&hcd->periodic_sched_ready); + DWC_LIST_INIT(&hcd->periodic_sched_assigned); + DWC_LIST_INIT(&hcd->periodic_sched_queued); +- ++ DWC_TAILQ_INIT(&hcd->completed_urb_list); + /* + * Create a host channel descriptor for each host channel implemented + * in the controller. Initialize the channel descriptor array. +@@ -906,6 +989,9 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) + + /* Initialize reset tasklet. */ + hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd); ++ ++ hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet", ++ completion_tasklet_func, hcd); + #ifdef DWC_DEV_SRPCAP + if (hcd->core_if->power_down == 2) { + /* Initialize Power on timer for Host power up in case hibernation */ +@@ -938,6 +1024,12 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) hcd->frame_list = NULL; hcd->frame_list_dma = 0; hcd->periodic_qh_count = 0; + + DWC_MEMSET(hcd->hub_port, 0, sizeof(hcd->hub_port)); ++#ifdef FIQ_DEBUG + DWC_MEMSET(hcd->hub_port_alloc, -1, sizeof(hcd->hub_port_alloc)); ++#endif + out: return retval; } -@@ -1124,7 +1133,12 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +@@ -1083,7 +1175,12 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) uint32_t hub_addr, port_addr; hc->do_split = 1; hc->xact_pos = qtd->isoc_split_pos; @@ -95001,7 +94350,7 @@ index fe03c43..ec00b13 100644 hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr); hc->hub_addr = (uint8_t) hub_addr; hc->port_addr = (uint8_t) port_addr; -@@ -1271,6 +1285,62 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +@@ -1230,6 +1327,65 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) hc->qh = qh; } @@ -95040,7 +94389,9 @@ index fe03c43..ec00b13 100644 + qh->skip_count = 0; + hcd->hub_port[hub_addr] |= 1 << port_addr; + fiq_print(FIQDBG_PORTHUB, "H%dP%d:A %d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); ++#ifdef FIQ_DEBUG + hcd->hub_port_alloc[hub_addr * 16 + port_addr] = dwc_otg_hcd_get_frame_number(hcd); ++#endif + return 0; + } +} @@ -95054,8 +94405,9 @@ index fe03c43..ec00b13 100644 + hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); + + hcd->hub_port[hub_addr] &= ~(1 << port_addr); ++#ifdef FIQ_DEBUG + hcd->hub_port_alloc[hub_addr * 16 + port_addr] = -1; -+ ++#endif + fiq_print(FIQDBG_PORTHUB, "H%dP%d:RO%d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); + +} @@ -95064,18 +94416,37 @@ index fe03c43..ec00b13 100644 /** * This function selects transactions from the HCD transfer schedule and * assigns them to available host channels. It is called from HCD interrupt -@@ -1304,11 +1374,22 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) +@@ -1243,9 +1399,10 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + { + dwc_list_link_t *qh_ptr; + dwc_otg_qh_t *qh; ++ dwc_otg_qtd_t *qtd; + int num_channels; + dwc_irqflags_t flags; +- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC(); ++ dwc_spinlock_t *channel_lock = hcd->channel_lock; + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; + + #ifdef DEBUG_SOF +@@ -1263,11 +1420,29 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) while (qh_ptr != &hcd->periodic_sched_ready && !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { + + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); + -+ if(qh->do_split && dwc_otg_hcd_allocate_port(hcd, qh)) -+ { -+ qh_ptr = DWC_LIST_NEXT(qh_ptr); -+ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); -+ continue; ++ if(qh->do_split) { ++ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); ++ if(!(qh->ep_type == UE_ISOCHRONOUS && ++ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID || ++ qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))) { ++ if(dwc_otg_hcd_allocate_port(hcd, qh)) ++ { ++ qh_ptr = DWC_LIST_NEXT(qh_ptr); ++ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); ++ continue; ++ } ++ } + } + if (microframe_schedule) { @@ -95087,7 +94458,7 @@ index fe03c43..ec00b13 100644 break; } hcd->available_host_channels--; -@@ -1329,8 +1410,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) +@@ -1288,8 +1463,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, &qh->qh_list_entry); DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); @@ -95096,36 +94467,57 @@ index fe03c43..ec00b13 100644 } /* -@@ -1369,10 +1448,19 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - qh->nak_frame = 0xffff; - } - } +@@ -1304,6 +1477,31 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + num_channels - hcd->periodic_channels) && + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { + ++ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); + -+ if (qh->do_split && dwc_otg_hcd_allocate_port(hcd, qh)) -+ { -+ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); -+ qh_ptr = DWC_LIST_NEXT(qh_ptr); -+ continue; ++ /* ++ * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission ++ * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed ++ * cheeky devices that just hold off using NAKs ++ */ ++ if (nak_holdoff_enable && qh->do_split) { ++ if (qh->nak_frame != 0xffff && ++ dwc_full_frame_num(qh->nak_frame) == ++ dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { ++ /* ++ * Revisit: Need to avoid trampling on periodic scheduling. ++ * Currently we are safe because g_np_count != g_np_sent whenever we hit this, ++ * but if this behaviour is changed then periodic endpoints will get a slower ++ * polling rate. ++ */ ++ g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; ++ qh_ptr = DWC_LIST_NEXT(qh_ptr); ++ continue; ++ } else { ++ qh->nak_frame = 0xffff; ++ } + } + if (microframe_schedule) { DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); if (hcd->available_host_channels < 1) { - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); -+ if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh); - break; - } - hcd->available_host_channels--; -@@ -1396,16 +1484,17 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) +@@ -1316,7 +1514,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + last_sel_trans_num_nonper_scheduled++; + #endif /* DEBUG_HOST_CHANNELS */ + } +- qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - g_np_sent++; + assign_and_init_hc(hcd, qh); + +@@ -1330,21 +1527,22 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + &qh->qh_list_entry); + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - if (ret_val == DWC_OTG_TRANSACTION_NONE) { - ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC; - } else { - ret_val = DWC_OTG_TRANSACTION_ALL; - } -- ++ g_np_sent++; + if (!microframe_schedule) hcd->non_periodic_channels++; } @@ -95140,7 +94532,12 @@ index fe03c43..ec00b13 100644 #ifdef DEBUG_HOST_CHANNELS last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels; #endif /* DEBUG_HOST_CHANNELS */ -@@ -1522,6 +1611,15 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) +- +- DWC_SPINLOCK_FREE(channel_lock); + return ret_val; + } + +@@ -1458,6 +1656,15 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); @@ -95156,7 +94553,7 @@ index fe03c43..ec00b13 100644 /* * Set a flag if we're queuing high-bandwidth in slave mode. * The flag prevents any halts to get into the request queue in -@@ -1651,6 +1749,15 @@ static void process_non_periodic_channels(dwc_otg_hcd_t * hcd) +@@ -1587,6 +1794,15 @@ static void process_non_periodic_channels(dwc_otg_hcd_t * hcd) qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t, qh_list_entry); @@ -95172,8 +94569,32 @@ index fe03c43..ec00b13 100644 status = queue_transaction(hcd, qh->channel, tx_status.b.nptxfspcavail); +@@ -3112,17 +3328,13 @@ dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd, + else + dwc_otg_urb = DWC_ALLOC(size); + +- if (NULL != dwc_otg_urb) +- dwc_otg_urb->packet_count = iso_desc_count; ++ if (dwc_otg_urb) ++ dwc_otg_urb->packet_count = iso_desc_count; + else { +- dwc_otg_urb->packet_count = 0; +- if (size != 0) { +- DWC_ERROR("**** DWC OTG HCD URB alloc - " +- "%salloc of %db failed\n", +- atomic_alloc?"atomic ":"", size); +- } +- } +- ++ DWC_ERROR("**** DWC OTG HCD URB alloc - " ++ "%salloc of %db failed\n", ++ atomic_alloc?"atomic ":"", size); ++ } + return dwc_otg_urb; + } + diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -index 0ba7558..de1ccb1 100644 +index bb4f67a..0007fa1 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h @@ -168,10 +168,10 @@ typedef enum dwc_otg_control_phase { @@ -95191,7 +94612,19 @@ index 0ba7558..de1ccb1 100644 } dwc_otg_transaction_type_e; struct dwc_otg_qh; -@@ -370,6 +370,8 @@ typedef struct dwc_otg_qh { +@@ -321,6 +321,11 @@ typedef struct dwc_otg_qh { + */ + uint16_t sched_frame; + ++ /* ++ ** Frame a NAK was received on this queue head, used to minimise NAK retransmission ++ */ ++ uint16_t nak_frame; ++ + /** (micro)frame at which last start split was initialized. */ + uint16_t start_split_frame; + +@@ -365,10 +370,19 @@ typedef struct dwc_otg_qh { uint16_t speed; uint16_t frame_usecs[8]; @@ -95200,18 +94633,45 @@ index 0ba7558..de1ccb1 100644 } dwc_otg_qh_t; DWC_CIRCLEQ_HEAD(hc_list, dwc_hc); -@@ -574,6 +576,10 @@ struct dwc_otg_hcd { + ++typedef struct urb_tq_entry { ++ struct urb *urb; ++ DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries; ++} urb_tq_entry_t; ++ ++DWC_TAILQ_HEAD(urb_list, urb_tq_entry); ++ + /** + * This structure holds the state of the HCD, including the non-periodic and + * periodic schedules. +@@ -546,9 +560,12 @@ struct dwc_otg_hcd { + /* Tasket to do a reset */ + dwc_tasklet_t *reset_tasklet; + ++ dwc_tasklet_t *completion_tasklet; ++ struct urb_list completed_urb_list; ++ + /* */ + dwc_spinlock_t *lock; +- ++ dwc_spinlock_t *channel_lock; + /** + * Private data that could be used by OS wrapper. + */ +@@ -559,6 +576,12 @@ struct dwc_otg_hcd { /** Frame List */ uint32_t *frame_list; + /** Hub - Port assignment */ -+ int hub_port[16]; -+ int hub_port_alloc[256]; ++ int hub_port[128]; ++#ifdef FIQ_DEBUG ++ int hub_port_alloc[2048]; ++#endif + /** Frame List DMA address */ dma_addr_t frame_list_dma; -@@ -604,12 +610,16 @@ extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t +@@ -589,6 +612,10 @@ extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, dwc_otg_transaction_type_e tr_type); @@ -95222,35 +94682,73 @@ index 0ba7558..de1ccb1 100644 /** @} */ /** @name Interrupt Handler Functions */ - /** @{ */ +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c +index 274967b..ee920c4 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c +@@ -276,7 +276,7 @@ void dump_frame_list(dwc_otg_hcd_t * hcd) + static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + { + dwc_irqflags_t flags; +- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC(); ++ dwc_spinlock_t *channel_lock = hcd->channel_lock; + + dwc_hc_t *hc = qh->channel; + if (dwc_qh_is_non_per(qh)) { +@@ -306,7 +306,6 @@ static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + dwc_memset(qh->desc_list, 0x00, + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh)); + } +- DWC_SPINLOCK_FREE(channel_lock); + } + + /** +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h +index 4823167..fb57db0 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h +@@ -113,6 +113,11 @@ extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd); + */ extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); --extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd, int32_t); -+extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd); - extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * - dwc_otg_hcd); - extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * + ++/** This function is used to handle the fast interrupt ++ * ++ */ ++extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void); ++ + /** + * Returns private data set by + * dwc_otg_hcd_set_priv_data function. diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index a27dacd..8e5789f 100644 +index b41e164..64d33a5 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -38,6 +38,7 @@ +@@ -34,6 +34,12 @@ - #include - #include + #include "dwc_otg_hcd.h" + #include "dwc_otg_regs.h" ++#include "dwc_otg_mphi_fix.h" ++ ++#include ++#include +#include - ++ extern bool microframe_schedule; -@@ -52,21 +53,295 @@ extern bool microframe_schedule; - void * dummy_send; - mphi_regs_t c_mphi_regs; +@@ -41,38 +47,487 @@ extern bool microframe_schedule; + * This file contains the implementation of the HCD Interrupt handlers. + */ + ++/* ++ * Some globals to communicate between the FIQ and INTERRUPT ++ */ ++ ++void * dummy_send; ++mphi_regs_t c_mphi_regs; +volatile void *dwc_regs_base; - int fiq_done, int_done; --int g_next_sched_frame, g_np_count, g_np_sent, g_work_expected; --static int mphi_int_count = 0 ; - --extern bool fiq_fix_enable, nak_holdoff_enable; ++int fiq_done, int_done; ++ +gintsts_data_t gintsts_saved = {.d32 = 0}; +hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; +hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; @@ -95259,12 +94757,12 @@ index a27dacd..8e5789f 100644 + +int g_next_sched_frame, g_np_count, g_np_sent; +static int mphi_int_count = 0 ; - - hcchar_data_t nak_hcchar; - hctsiz_data_t nak_hctsiz; - hcsplt_data_t nak_hcsplt; - int nak_count; - ++ ++hcchar_data_t nak_hcchar; ++hctsiz_data_t nak_hctsiz; ++hcsplt_data_t nak_hcsplt; ++int nak_count; ++ +int complete_sched[MAX_EPS_CHANNELS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +int split_start_frame[MAX_EPS_CHANNELS]; +int queued_port[MAX_EPS_CHANNELS]; @@ -95272,7 +94770,7 @@ index a27dacd..8e5789f 100644 +#ifdef FIQ_DEBUG +char buffer[1000*16]; +int wptr; -+void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) ++void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) +{ + FIQDBG_T dbg_lvl_req = FIQDBG_PORTHUB; + va_list args; @@ -95296,7 +94794,7 @@ index a27dacd..8e5789f 100644 +} +#endif + -+void fiq_queue_request(int channel, int odd_frame) ++void notrace fiq_queue_request(int channel, int odd_frame) +{ + hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; + hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; @@ -95342,7 +94840,7 @@ index a27dacd..8e5789f 100644 +*/ +int diff; + -+int fiq_sof_handle(hfnum_data_t hfnum) ++int notrace fiq_sof_handle(hfnum_data_t hfnum) +{ + int handled = 0; + int i; @@ -95401,12 +94899,12 @@ index a27dacd..8e5789f 100644 + return handled; +} + -+int port_id(hcsplt_data_t hcsplt) ++int notrace port_id(hcsplt_data_t hcsplt) +{ + return hcsplt.b.prtaddr + (hcsplt.b.hubaddr << 8); +} + -+int fiq_hcintr_handle(int channel, hfnum_data_t hfnum) ++int notrace fiq_hcintr_handle(int channel, hfnum_data_t hfnum) +{ + hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; + hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; @@ -95519,6 +95017,27 @@ index a27dacd..8e5789f 100644 + } + } + } ++ else ++ { ++ /* ++ * If we have any of NAK, ACK, Datatlgerr active on a ++ * non-split channel, the sole reason is to reset error ++ * counts for a previously broken transaction. The FIQ ++ * will thrash on NAK IN and ACK OUT in particular so ++ * handle it "once" and allow the IRQ to do the rest. ++ */ ++ hcint.d32 &= hcintmsk.d32; ++ if(hcint.b.nak) ++ { ++ hcintmsk.b.nak = 0; ++ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); ++ } ++ if (hcint.b.ack) ++ { ++ hcintmsk.b.ack = 0; ++ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); ++ } ++ } + + // Clear the interrupt, this will also clear the HAINT bit + FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32); @@ -95535,32 +95054,23 @@ index a27dacd..8e5789f 100644 +gintsts_data_t triggered, handled, keep; +hfnum_data_t hfnum; + - void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void) - { -- gintsts_data_t gintsts; -- hfnum_data_t hfnum; - - /* entry takes care to store registers we will be treading on here */ - asm __volatile__ ( -@@ -74,43 +349,112 @@ void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void) - /* stash FIQ and normal regs */ - "stmdb sp!, {r0-r12, lr};" - /* !! THIS SETS THE FRAME, adjust to > sizeof locals */ -- "sub fp, ip, #256 ;" ++void __attribute__ ((naked)) notrace dwc_otg_hcd_handle_fiq(void) ++{ ++ ++ /* entry takes care to store registers we will be treading on here */ ++ asm __volatile__ ( ++ "mov ip, sp ;" ++ /* stash FIQ and normal regs */ ++ "stmdb sp!, {r0-r12, lr};" ++ /* !! THIS SETS THE FRAME, adjust to > sizeof locals */ + "sub fp, ip, #512 ;" - ); - -- fiq_done++; -- gintsts.d32 = FIQ_READ_IO_ADDRESS(USB_BASE + 0x14) & FIQ_READ_IO_ADDRESS(USB_BASE + 0x18); -- hfnum.d32 = FIQ_READ_IO_ADDRESS(USB_BASE + 0x408); -- -- if(gintsts.d32) ++ ); ++ + // Cannot put local variables at the beginning of the function + // because otherwise 'C' will play with the stack pointer. any locals + // need to be inside the following block + do - { -- if(gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) ++ { + fiq_done++; + gintsts.d32 = FIQ_READ(dwc_regs_base + 0x14); + gintmsk.d32 = FIQ_READ(dwc_regs_base + 0x18); @@ -95572,16 +95082,7 @@ index a27dacd..8e5789f 100644 + fiq_print(FIQDBG_INT, "%08x", gintsts.d32); + fiq_print(FIQDBG_INT, "%08x", gintmsk.d32); + if(gintsts.d32) - { -- /* -- * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet -- * g_next_sched_frame is the next frame we have periodic packets for -- * -- * if neither of these are required for this frame then just clear the interrupt -- */ -- gintsts.d32 = 0; -- gintsts.b.sofintr = 1; -- FIQ_WRITE_IO_ADDRESS((USB_BASE + 0x14), gintsts.d32); ++ { + // If port enabled + if((FIQ_READ(dwc_regs_base + 0x440) & 0xf) == 0x5) + { @@ -95634,8 +95135,7 @@ index a27dacd..8e5789f 100644 + /* Make sure we keep the channel interrupt unmasked when triggering the IRQ */ + keep.b.hcintr = 1; + } - -- g_work_expected = 0; ++ + { + gintsts_data_t gintsts = { .b.hcintr = 1 }; + @@ -95648,8 +95148,7 @@ index a27dacd..8e5789f 100644 + { + last_sof = -1; + } - } -- else ++ } + + // Mask out the interrupts triggered - those handled - don't mask out the ones we want to keep + gintmsk.d32 = keep.d32 | (gintmsk.d32 & ~(triggered.d32 & ~handled.d32)); @@ -95659,35 +95158,52 @@ index a27dacd..8e5789f 100644 + + // Clear and save any unhandled interrupts and trigger the interrupt + if(gintsts_saved.d32) - { -- g_work_expected = 1; - /* To enable the MPHI interrupt (INT 32) - */ -- FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send); ++ { ++ /* To enable the MPHI interrupt (INT 32) ++ */ + FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send); - FIQ_WRITE( c_mphi_regs.outddb, (1 << 29)); - - mphi_int_count++; -- /* Clear the USB global interrupt so we don't just sit in the FIQ */ -- FIQ_MODIFY_IO_ADDRESS((USB_BASE + 0x8),1,0); -- - } - } ++ FIQ_WRITE( c_mphi_regs.outddb, (1 << 29)); ++ ++ mphi_int_count++; ++ } ++ } + while(0); + - mb(); - - /* exit back to normal mode restoring everything */ -@@ -133,6 +477,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) ++ mb(); ++ ++ /* exit back to normal mode restoring everything */ ++ asm __volatile__ ( ++ /* return FIQ regs back to pristine state ++ * and get normal regs back ++ */ ++ "ldmia sp!, {r0-r12, lr};" ++ ++ /* return */ ++ "subs pc, lr, #4;" ++ ); ++} ++ + /** This function handles interrupts for the HCD. */ + int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) + { + int retval = 0; ++ static int last_time; dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; gintsts_data_t gintsts; + gintmsk_data_t gintmsk; - hfnum_data_t hfnum; - ++ hfnum_data_t hfnum; ++ #ifdef DEBUG -@@ -140,6 +485,9 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; +- //GRAYG: debugging +- if (NULL == global_regs) { +- DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p " +- "core_if=%p\n", +- dwc_otg_hcd, global_regs); +- return retval; +- } #endif + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts); @@ -95695,8 +95211,9 @@ index a27dacd..8e5789f 100644 + /* Exit from ISR if core is hibernated */ if (core_if->hibernation_suspend == 1) { - goto exit_handler_routine; -@@ -147,11 +495,18 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) +- return retval; ++ goto exit_handler_routine; + } DWC_SPINLOCK(dwc_otg_hcd->lock); /* Check if HOST Mode */ if (dwc_otg_is_host_mode(core_if)) { @@ -95707,7 +95224,9 @@ index a27dacd..8e5789f 100644 + gintsts_saved.d32 = 0; + local_fiq_enable(); if (!gintsts.d32) { - goto exit_handler_routine; +- DWC_SPINUNLOCK(dwc_otg_hcd->lock); +- return 0; ++ goto exit_handler_routine; } + gintsts.d32 &= gintmsk.d32; + @@ -95716,22 +95235,26 @@ index a27dacd..8e5789f 100644 /* Don't print debug message in the interrupt handler on SOF */ #ifndef DEBUG_SOF if (gintsts.d32 != DWC_SOF_INTR_MASK) -@@ -171,11 +526,12 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) - { - /* Note, we should never get here if the FIQ is doing it's job properly*/ -- retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd, g_work_expected); -+ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); +@@ -88,10 +543,16 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) + "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n", + gintsts.d32, core_if); + #endif +- +- if (gintsts.b.sofintr) { ++ hfnum.d32 = DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum); ++ if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) ++ { ++ /* Note, we should never get here if the FIQ is doing it's job properly*/ + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); } - else if (gintsts.b.sofintr) { -- retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd, g_work_expected); ++ else if (gintsts.b.sofintr) { + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); - } ++ } + if (gintsts.b.rxstsqlvl) { retval |= dwc_otg_hcd_handle_rx_status_q_level_intr -@@ -190,7 +546,10 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) +@@ -106,7 +567,10 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) /** @todo Implement i2cintr handler. */ } if (gintsts.b.portintr) { @@ -95742,22 +95265,19 @@ index a27dacd..8e5789f 100644 } if (gintsts.b.hcintr) { retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd); -@@ -227,26 +586,35 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) +@@ -138,11 +602,48 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) + #endif - if (fiq_fix_enable) - { -- /* Clear the MPHI interrupt */ -- DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16)); -- if (mphi_int_count >= 60) + } ++ ++exit_handler_routine: ++ ++ if (fiq_fix_enable) ++ { + local_fiq_disable(); + // Make sure that we don't clear the interrupt if we've still got pending work to do + if(gintsts_saved.d32 == 0) - { -- DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16))); -- while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17))) -- ; -- DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); -- mphi_int_count = 0; ++ { + /* Clear the MPHI interrupt */ + DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16)); + if (mphi_int_count >= 60) @@ -95769,8 +95289,7 @@ index a27dacd..8e5789f 100644 + mphi_int_count = 0; + } + int_done++; - } -- int_done++; ++ } + + // Unmask handled interrupts + FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); @@ -95778,34 +95297,34 @@ index a27dacd..8e5789f 100644 + + local_fiq_enable(); + - if((jiffies / HZ) > last_time) - { - /* Once a second output the fiq and irq numbers, useful for debug */ - last_time = jiffies / HZ; - DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done); - } -- -- /* Re-Enable FIQ interrupt from USB peripheral */ -- DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1); - } - ++ if((jiffies / HZ) > last_time) ++ { ++ /* Once a second output the fiq and irq numbers, useful for debug */ ++ last_time = jiffies / HZ; ++ DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done); ++ } ++ } ++ DWC_SPINUNLOCK(dwc_otg_hcd->lock); -@@ -294,13 +662,12 @@ static inline void track_missed_sofs(uint16_t curr_frame_number) - * (micro)frame. Periodic transactions may be queued to the controller for the - * next (micro)frame. - */ --int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd, int32_t work_expected) -+int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) - { - hfnum_data_t hfnum; + return retval; + } + + #ifdef DWC_TRACK_MISSED_SOFS ++ + #warning Compiling code to track missed SOFs + #define FRAME_NUM_ARRAY_SIZE 1000 + /** +@@ -188,7 +689,8 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) dwc_list_link_t *qh_entry; dwc_otg_qh_t *qh; dwc_otg_transaction_type_e tr_type; - gintsts_data_t gintsts = {.d32 = 0 }; - int did_something = 0; - int32_t next_sched_frame = -1; ++ int did_something = 0; ++ int32_t next_sched_frame = -1; -@@ -326,6 +693,7 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd, int32_t work_expected) + hfnum.d32 = + DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); +@@ -212,17 +714,31 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry); qh_entry = qh_entry->next; if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) { @@ -95813,25 +95332,31 @@ index a27dacd..8e5789f 100644 /* * Move QH to the ready list to be executed next * (micro)frame. -@@ -351,15 +719,10 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd, int32_t work_expected) - dwc_otg_hcd_queue_transactions(hcd, tr_type); - did_something = 1; + */ + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, + &qh->qh_list_entry); ++ ++ did_something = 1; ++ } ++ else ++ { ++ if(next_sched_frame < 0 || dwc_frame_num_le(qh->sched_frame, next_sched_frame)) ++ { ++ next_sched_frame = qh->sched_frame; ++ } + } + } ++ ++ g_next_sched_frame = next_sched_frame; ++ + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE) { + dwc_otg_hcd_queue_transactions(hcd, tr_type); ++ did_something = 1; } -- if(work_expected && !did_something) -- DWC_DEBUGPL(DBG_USER, "Nothing to do !! frame = %x, g_next_sched_frame = %x\n", (int) hfnum.b.frnum, g_next_sched_frame); -- if(!work_expected && did_something) -- DWC_DEBUGPL(DBG_USER, "Unexpected work done !! frame = %x, g_next_sched_frame = %x\n", (int) hfnum.b.frnum, g_next_sched_frame); -- /* Clear interrupt */ -- gintsts.b.sofintr = 1; -- DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); -+ //gintsts.b.sofintr = 1; -+ //DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); - - return 1; - } -@@ -643,6 +1006,15 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd) +@@ -511,6 +1027,15 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd) haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); @@ -95847,7 +95372,7 @@ index a27dacd..8e5789f 100644 for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) { if (haint.b2.chint & (1 << i)) { retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i); -@@ -683,7 +1055,10 @@ static uint32_t get_actual_xfer_length(dwc_hc_t * hc, +@@ -551,7 +1076,10 @@ static uint32_t get_actual_xfer_length(dwc_hc_t * hc, *short_read = (hctsiz.b.xfersize != 0); } } else if (hc->qh->do_split) { @@ -95859,7 +95384,7 @@ index a27dacd..8e5789f 100644 } else { length = hc->xfer_len; } -@@ -727,7 +1102,6 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc, +@@ -595,7 +1123,6 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc, DWC_OTG_HC_XFER_COMPLETE, &short_read); @@ -95867,17 +95392,33 @@ index a27dacd..8e5789f 100644 /* non DWORD-aligned buffer case handling. */ if (hc->align_buff && xfer_length && hc->ep_is_in) { dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, -@@ -930,6 +1304,9 @@ static void release_channel(dwc_otg_hcd_t * hcd, +@@ -797,11 +1324,24 @@ static void release_channel(dwc_otg_hcd_t * hcd, + dwc_otg_transaction_type_e tr_type; int free_qtd; dwc_irqflags_t flags; - dwc_spinlock_t *channel_lock = hcd->channel_lock; +- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC(); ++ dwc_spinlock_t *channel_lock = hcd->channel_lock; +#ifdef FIQ_DEBUG + int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0; +#endif ++ int hog_port = 0; DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", __func__, hc->hc_num, halt_status, hc->xfer_len); -@@ -1008,9 +1385,24 @@ static void release_channel(dwc_otg_hcd_t * hcd, + ++ if(fiq_split_enable && hc->do_split) { ++ if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) { ++ if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID || ++ hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) { ++ hog_port = 1; ++ } ++ } ++ } ++ + switch (halt_status) { + case DWC_OTG_HC_XFER_URB_COMPLETE: + free_qtd = 1; +@@ -876,15 +1416,32 @@ static void release_channel(dwc_otg_hcd_t * hcd, DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); hcd->available_host_channels++; @@ -95892,429 +95433,44 @@ index a27dacd..8e5789f 100644 + fiq_print(FIQDBG_ERR, "PRTNOTAL"); + //BUG(); + } -+ -+ hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); -+ hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; -+ -+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); ++ if(!hog_port && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC || ++ hc->ep_type == DWC_OTG_EP_TYPE_INTR)) { ++ hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); ++#ifdef FIQ_DEBUG ++ hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; ++#endif ++ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); ++ } + } + /* Try to queue more transfers now that there's a free channel. */ tr_type = dwc_otg_hcd_select_transactions(hcd); if (tr_type != DWC_OTG_TRANSACTION_NONE) { -@@ -1633,8 +2025,10 @@ static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd, - hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { - int frnum = dwc_otg_hcd_get_frame_number(hcd); - -+ // With the FIQ running we only ever see the failed NYET - if (dwc_full_frame_num(frnum) != -- dwc_full_frame_num(hc->qh->sched_frame)) { -+ dwc_full_frame_num(hc->qh->sched_frame) || -+ fiq_split_enable) { - /* - * No longer in the same full speed frame. - * Treat this as a transaction error. -@@ -2012,10 +2406,10 @@ static inline int halt_status_ok(dwc_otg_hcd_t * hcd, - static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - dwc_hc_t * hc, - dwc_otg_hc_regs_t * hc_regs, -- dwc_otg_qtd_t * qtd) -+ dwc_otg_qtd_t * qtd, -+ hcint_data_t hcint, -+ hcintmsk_data_t hcintmsk) - { -- hcint_data_t hcint; -- hcintmsk_data_t hcintmsk; - int out_nak_enh = 0; - - /* For core with OUT NAK enhancement, the flow for high- -@@ -2047,8 +2441,11 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + dwc_otg_hcd_queue_transactions(hcd, tr_type); } +- DWC_SPINLOCK_FREE(channel_lock); + } - /* Read the HCINTn register to determine the cause for the halt. */ -- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -- hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); -+ if(!fiq_split_enable) -+ { -+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -+ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); -+ } - - if (hcint.b.xfercomp) { - /** @todo This is here because of a possible hardware bug. Spec -@@ -2161,13 +2558,15 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, - dwc_hc_t * hc, - dwc_otg_hc_regs_t * hc_regs, -- dwc_otg_qtd_t * qtd) -+ dwc_otg_qtd_t * qtd, -+ hcint_data_t hcint, -+ hcintmsk_data_t hcintmsk) - { - DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " - "Channel Halted--\n", hc->hc_num); - - if (hcd->core_if->dma_enable) { -- handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd); -+ handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd, hcint, hcintmsk); - } else { - #ifdef DEBUG - if (!halt_status_ok(hcd, hc, hc_regs, qtd)) { -@@ -2184,7 +2583,7 @@ static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, - int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - { - int retval = 0; -- hcint_data_t hcint; -+ hcint_data_t hcint, hcint_orig; - hcintmsk_data_t hcintmsk; - dwc_hc_t *hc; - dwc_otg_hc_regs_t *hc_regs; -@@ -2197,12 +2596,23 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); - - hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -+ hcint_orig = hcint; - hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); - DWC_DEBUGPL(DBG_HCDV, - " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", - hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); - hcint.d32 = hcint.d32 & hcintmsk.d32; - -+ if(fiq_split_enable) -+ { -+ // replace with the saved interrupts from the fiq handler -+ local_fiq_disable(); -+ hcint_orig.d32 = hcint_saved[num].d32; -+ hcint.d32 = hcint_orig.d32 & hcintmsk_saved[num].d32; -+ hcint_saved[num].d32 = 0; -+ local_fiq_enable(); -+ } -+ - if (!dwc_otg_hcd->core_if->dma_enable) { - if (hcint.b.chhltd && hcint.d32 != 0x2) { - hcint.b.chhltd = 0; -@@ -2220,7 +2630,7 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - hcint.b.nyet = 0; - } - if (hcint.b.chhltd) { -- retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd); -+ retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd, hcint_orig, hcintmsk_saved[num]); - } - if (hcint.b.ahberr) { - retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index 5e6a26a..d1c5c2b 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -392,7 +392,11 @@ static struct dwc_otg_hcd_function_ops hcd_fops = { - static struct fiq_handler fh = { - .name = "usb_fiq", - }; --static uint8_t fiqStack[1024]; -+struct fiq_stack_s { -+ int magic1; -+ uint8_t stack[2048]; -+ int magic2; -+} fiq_stack; - - extern mphi_regs_t c_mphi_regs; /** -@@ -434,9 +438,11 @@ int hcd_init(dwc_bus_dev_t *_dev) - memset(®s,0,sizeof(regs)); - regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq; - regs.ARM_r9 = (long)0; -- regs.ARM_sp = (long)fiqStack + sizeof(fiqStack) - 4; -+ regs.ARM_sp = (long)fiq_stack.stack + sizeof(fiq_stack.stack) - 4; - set_fiq_regs(®s); -- } -+ fiq_stack.magic1 = 0xdeadbeef; -+ fiq_stack.magic2 = 0xaa995566; -+ } +@@ -1295,6 +1852,17 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, + "NAK Received--\n", hc->hc_num); /* - * Allocate memory for the base HCD plus the DWC OTG HCD. -@@ -459,6 +465,8 @@ int hcd_init(dwc_bus_dev_t *_dev) - - if (fiq_fix_enable) - { -+ volatile extern void *dwc_regs_base; ++ * When we get bulk NAKs then remember this so we holdoff on this qh until ++ * the beginning of the next frame ++ */ ++ switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { ++ case UE_BULK: ++ case UE_CONTROL: ++ if (nak_holdoff_enable) ++ hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd); ++ } + - //Set the mphi periph to the required registers - c_mphi_regs.base = otg_dev->os_dep.mphi_base; - c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; -@@ -466,6 +474,8 @@ int hcd_init(dwc_bus_dev_t *_dev) - c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; - c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; - -+ dwc_regs_base = otg_dev->os_dep.base; -+ - //Enable mphi peripheral - writel((1<<31),c_mphi_regs.ctrl); - #ifdef DEBUG -@@ -839,6 +849,8 @@ static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) - usb_hcd_unlink_urb_from_ep(hcd, urb); - #endif - DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags); -+ -+ - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - usb_hcd_giveback_urb(hcd, urb); - #else -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index 1554be5..7b92025 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -41,6 +41,7 @@ - - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" -+#include "dwc_otg_mphi_fix.h" - - extern bool microframe_schedule; - -@@ -191,6 +192,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) - dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr, - hub_port); - qh->do_split = 1; -+ qh->skip_count = 0; - } - - if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) { -@@ -737,6 +739,9 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - hcd->non_periodic_qh_ptr->next; - } - DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); -+ -+ // If we've removed the last non-periodic entry then there are none left! -+ g_np_count = g_np_sent; - } else { - deschedule_periodic(hcd, qh); - hcd->periodic_qh_count--; -@@ -766,21 +771,21 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, - { - if (dwc_qh_is_non_per(qh)) { - -- dwc_otg_qh_t *qh_tmp; -- dwc_list_link_t *qh_list; -- DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) -- { -- qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); -- if(qh_tmp == qh) -+ dwc_otg_qh_t *qh_tmp; -+ dwc_list_link_t *qh_list; -+ DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) - { -- /* -- * FIQ is being disabled because this one nevers gets a np_count increment -- * This is still not absolutely correct, but it should fix itself with -- * just an unnecessary extra interrupt -- */ -- g_np_sent = g_np_count; -+ qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); -+ if(qh_tmp == qh) -+ { -+ /* -+ * FIQ is being disabled because this one nevers gets a np_count increment -+ * This is still not absolutely correct, but it should fix itself with -+ * just an unnecessary extra interrupt -+ */ -+ g_np_sent = g_np_count; -+ } - } -- } - - - dwc_otg_hcd_qh_remove(hcd, qh); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -index 660d50f..ca17379 100755 ---- a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -@@ -1,10 +1,7 @@ - #ifndef __DWC_OTG_MPHI_FIX_H__ - #define __DWC_OTG_MPHI_FIX_H__ -- --#define FIQ_WRITE_IO_ADDRESS(_addr_,_data_) *(volatile uint32_t *) IO_ADDRESS(_addr_) = _data_ --#define FIQ_READ_IO_ADDRESS(_addr_) *(volatile uint32_t *) IO_ADDRESS(_addr_) --#define FIQ_MODIFY_IO_ADDRESS(_addr_,_clear_,_set_) FIQ_WRITE_IO_ADDRESS(_addr_ , (FIQ_READ_IO_ADDRESS(_addr_)&~_clear_)|_set_) --#define FIQ_WRITE(_addr_,_data_) *(volatile uint32_t *) _addr_ = _data_ -+#define FIQ_WRITE(_addr_,_data_) (*(volatile uint32_t *) (_addr_) = (_data_)) -+#define FIQ_READ(_addr_) (*(volatile uint32_t *) (_addr_)) - - typedef struct { - volatile void* base; -@@ -18,7 +15,7 @@ void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_n - void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name); - void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); - -- -+extern gintsts_data_t gintsts_saved; - - #ifdef DEBUG - #define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__) -@@ -30,7 +27,22 @@ void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); - #define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) - #define DWC_DBG_PRINT_OTG_INT(_arg_) - -+#endif -+ -+typedef enum { -+ FIQDBG_SCHED = (1 << 0), -+ FIQDBG_INT = (1 << 1), -+ FIQDBG_ERR = (1 << 2), -+ FIQDBG_PORTHUB = (1 << 3), -+} FIQDBG_T; - -+void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...); -+#ifdef FIQ_DEBUG -+#define fiq_print _fiq_print -+#else -+#define fiq_print(x, y, ...) - #endif - -+extern bool fiq_fix_enable, nak_holdoff_enable, fiq_split_enable; -+ - #endif -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c -index 1b1f83c..c8590b5 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c -@@ -4276,7 +4276,7 @@ do { \ - && (pcd->ep0state == EP0_OUT_DATA_PHASE)) - status.d32 = core_if->dev_if->out_desc_addr->status.d32; - if (pcd->ep0state == EP0_OUT_STATUS_PHASE) -- status.d32 = status.d32 = core_if->dev_if-> -+ status.d32 = core_if->dev_if-> - out_desc_addr->status.d32; - - if (status.b.sr) { --- -1.9.3 - - -From 6725eee673ff4ac564431363988316b0709cf885 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 3 Jul 2013 11:39:46 +0100 -Subject: [PATCH 038/124] dwc_otg: fix device attributes and avoid kernel - warnings on boot - ---- - drivers/usb/host/dwc_otg/dwc_otg_attr.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.c b/drivers/usb/host/dwc_otg/dwc_otg_attr.c -index fab2961..af1cd4d 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_attr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c -@@ -909,7 +909,7 @@ static ssize_t regdump_show(struct device *_dev, - return sprintf(buf, "Register Dump\n"); - } - --DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0); -+DEVICE_ATTR(regdump, S_IRUGO, regdump_show, 0); - - /** - * Dump global registers and either host or device registers (depending on the -@@ -925,7 +925,7 @@ static ssize_t spramdump_show(struct device *_dev, - return sprintf(buf, "SPRAM Dump\n"); - } - --DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0); -+DEVICE_ATTR(spramdump, S_IRUGO, spramdump_show, 0); - - /** - * Dump the current hcd state. -@@ -940,7 +940,7 @@ static ssize_t hcddump_show(struct device *_dev, - return sprintf(buf, "HCD Dump\n"); - } - --DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0); -+DEVICE_ATTR(hcddump, S_IRUGO, hcddump_show, 0); - - /** - * Dump the average frame remaining at SOF. This can be used to -@@ -958,7 +958,7 @@ static ssize_t hcd_frrem_show(struct device *_dev, - return sprintf(buf, "HCD Dump Frame Remaining\n"); - } - --DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0); -+DEVICE_ATTR(hcd_frrem, S_IRUGO, hcd_frrem_show, 0); - - /** - * Displays the time required to read the GNPTXFSIZ register many times (the -@@ -986,7 +986,7 @@ static ssize_t rd_reg_test_show(struct device *_dev, - RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); - } - --DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0); -+DEVICE_ATTR(rd_reg_test, S_IRUGO, rd_reg_test_show, 0); - - /** - * Displays the time required to write the GNPTXFSIZ register many times (the -@@ -1014,7 +1014,7 @@ static ssize_t wr_reg_test_show(struct device *_dev, - RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); - } - --DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0); -+DEVICE_ATTR(wr_reg_test, S_IRUGO, wr_reg_test_show, 0); - - #ifdef CONFIG_USB_DWC_OTG_LPM - --- -1.9.3 - - -From c4e3fff19c82f3273483af030ec921b6413f28a1 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 15 Jul 2013 23:55:52 +0100 -Subject: [PATCH 039/124] dcw_otg: avoid logging function that can cause panics - -See: https://github.com/raspberrypi/firmware/issues/21 -Thanks to cleverca22 for fix ---- - drivers/usb/host/dwc_otg/dwc_otg_attr.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.c b/drivers/usb/host/dwc_otg/dwc_otg_attr.c -index af1cd4d..9da0c92 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_attr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c -@@ -920,7 +920,7 @@ static ssize_t spramdump_show(struct device *_dev, - { - dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev); - -- dwc_otg_dump_spram(otg_dev->core_if); -+ //dwc_otg_dump_spram(otg_dev->core_if); - - return sprintf(buf, "SPRAM Dump\n"); - } --- -1.9.3 - - -From 435734b14373f0c59ff930ab22104304f32b52c9 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Sat, 13 Jul 2013 20:41:26 +0100 -Subject: [PATCH 040/124] dwc_otg: mask correct interrupts after transaction - error recovery - -The dwc_otg driver will unmask certain interrupts on a transaction -that previously halted in the error state in order to reset the -QTD error count. The various fine-grained interrupt handlers do not -consider that other interrupts besides themselves were unmasked. - -By disabling the two other interrupts only ever enabled in DMA mode -for this purpose, we can avoid unnecessary function calls in the -IRQ handler. This will also prevent an unneccesary FIQ interrupt -from being generated if the FIQ is enabled. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 8e5789f..fd73e41 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -1851,7 +1851,11 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, ++ /* + * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and + * interrupt. Re-start the SSPLIT transfer. + */ +@@ -1316,7 +1884,11 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, * transfers in DMA mode for the sole purpose of * resetting the error count after a transaction error * occurs. The core will continue transferring data. @@ -96326,7 +95482,7 @@ index 8e5789f..fd73e41 100644 qtd->error_count = 0; goto handle_nak_done; } -@@ -1963,6 +1967,15 @@ static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd, +@@ -1428,6 +2000,15 @@ static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd, halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK); } } else { @@ -96342,10 +95498,37 @@ index 8e5789f..fd73e41 100644 qtd->error_count = 0; if (hc->qh->ping_state) { -@@ -2328,6 +2341,14 @@ static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd, - qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); - halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); - } else if (hc->ep_is_in) { +@@ -1490,8 +2071,10 @@ static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd, + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + int frnum = dwc_otg_hcd_get_frame_number(hcd); + ++ // With the FIQ running we only ever see the failed NYET + if (dwc_full_frame_num(frnum) != +- dwc_full_frame_num(hc->qh->sched_frame)) { ++ dwc_full_frame_num(hc->qh->sched_frame) || ++ fiq_split_enable) { + /* + * No longer in the same full speed frame. + * Treat this as a transaction error. +@@ -1778,13 +2361,28 @@ static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd, + dwc_otg_qtd_t * qtd) + { + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " +- "Data Toggle Error--\n", hc->hc_num); ++ "Data Toggle Error on %s transfer--\n", ++ hc->hc_num, (hc->ep_is_in ? "IN" : "OUT")); + +- if (hc->ep_is_in) { ++ /* Data toggles on split transactions cause the hc to halt. ++ * restart transfer */ ++ if(hc->qh->do_split) ++ { ++ qtd->error_count++; ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ update_urb_state_xfer_intr(hc, hc_regs, ++ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ } else if (hc->ep_is_in) { + /* An unmasked data toggle error on a non-split DMA transaction is + * for the sole purpose of resetting error counts. Disable other + * interrupts unmasked for the same reason. @@ -96355,487 +95538,50 @@ index 8e5789f..fd73e41 100644 + disable_hc_int(hc_regs, nak); + } qtd->error_count = 0; +- } else { +- DWC_ERROR("Data Toggle Error on OUT transfer," +- "channel %d\n", hc->hc_num); } --- -1.9.3 - - -From f053f841857ecff85c8d0e3b0ad16d3a99247144 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Sat, 13 Jul 2013 21:48:41 +0100 -Subject: [PATCH 041/124] dwc_otg: fiq: prevent FIQ thrash and incorrect state - passing to IRQ - -In the case of a transaction to a device that had previously aborted -due to an error, several interrupts are enabled to reset the error -count when a device responds. This has the side-effect of making the -FIQ thrash because the hardware will generate multiple instances of -a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK -on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the -associated interrupts. - -Additionally, on non-split transactions make sure that only unmasked -interrupts are cleared. This caused a hard-to-trigger but serious -race condition when you had the combination of an endpoint awaiting -error recovery and a transaction completed on an endpoint - due to -the sequencing and timing of interrupts generated by the dwc_otg core, -it was possible to confuse the IRQ handler. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index fd73e41..2ec0565 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -324,6 +324,27 @@ int fiq_hcintr_handle(int channel, hfnum_data_t hfnum) - } - } + disable_hc_int(hc_regs, datatglerr); +@@ -1862,10 +2460,10 @@ static inline int halt_status_ok(dwc_otg_hcd_t * hcd, + static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, +- dwc_otg_qtd_t * qtd) ++ dwc_otg_qtd_t * qtd, ++ hcint_data_t hcint, ++ hcintmsk_data_t hcintmsk) + { +- hcint_data_t hcint; +- hcintmsk_data_t hcintmsk; + int out_nak_enh = 0; + + /* For core with OUT NAK enhancement, the flow for high- +@@ -1897,8 +2495,11 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, } -+ else + + /* Read the HCINTn register to determine the cause for the halt. */ +- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); +- hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); ++ if(!fiq_split_enable) + { -+ /* -+ * If we have any of NAK, ACK, Datatlgerr active on a -+ * non-split channel, the sole reason is to reset error -+ * counts for a previously broken transaction. The FIQ -+ * will thrash on NAK IN and ACK OUT in particular so -+ * handle it "once" and allow the IRQ to do the rest. -+ */ -+ hcint.d32 &= hcintmsk.d32; -+ if(hcint.b.nak) -+ { -+ hcintmsk.b.nak = 0; -+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); -+ } -+ if (hcint.b.ack) -+ { -+ hcintmsk.b.ack = 0; -+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); -+ } ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); + } - // Clear the interrupt, this will also clear the HAINT bit - FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32); --- -1.9.3 - - -From 67326308ef03dabbddc66255d13c6aa479b20ac8 Mon Sep 17 00:00:00 2001 -From: Gordon Hollingworth -Date: Mon, 8 Jul 2013 04:12:19 +0100 -Subject: [PATCH 042/124] Fix function tracing - ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 2ec0565..083b1c3 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -77,7 +77,7 @@ int queued_port[MAX_EPS_CHANNELS]; - #ifdef FIQ_DEBUG - char buffer[1000*16]; - int wptr; --void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) -+void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) - { - FIQDBG_T dbg_lvl_req = FIQDBG_PORTHUB; - va_list args; -@@ -101,7 +101,7 @@ void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) - } - #endif - --void fiq_queue_request(int channel, int odd_frame) -+void notrace fiq_queue_request(int channel, int odd_frame) - { - hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; - hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; -@@ -147,7 +147,7 @@ static int last_sof = -1; - */ - int diff; - --int fiq_sof_handle(hfnum_data_t hfnum) -+int notrace fiq_sof_handle(hfnum_data_t hfnum) - { - int handled = 0; - int i; -@@ -206,12 +206,12 @@ int fiq_sof_handle(hfnum_data_t hfnum) - return handled; - } - --int port_id(hcsplt_data_t hcsplt) -+int notrace port_id(hcsplt_data_t hcsplt) - { - return hcsplt.b.prtaddr + (hcsplt.b.hubaddr << 8); - } - --int fiq_hcintr_handle(int channel, hfnum_data_t hfnum) -+int notrace fiq_hcintr_handle(int channel, hfnum_data_t hfnum) - { - hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; - hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; -@@ -361,7 +361,7 @@ gintmsk_data_t gintmsk; - gintsts_data_t triggered, handled, keep; - hfnum_data_t hfnum; - --void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void) -+void __attribute__ ((naked)) notrace dwc_otg_hcd_handle_fiq(void) - { - - /* entry takes care to store registers we will be treading on here */ --- -1.9.3 - - -From bb2ad210ca2185bda62c4ab8709bb2643b4ba780 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Thu, 18 Jul 2013 16:32:41 +0100 -Subject: [PATCH 043/124] dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue - ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 53 ++++++++++++++-------------- - 1 file changed, 26 insertions(+), 27 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index d1c5c2b..315c803 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -733,9 +733,9 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, - if(dwc_otg_urb == NULL) - return -ENOMEM; - -- urb->hcpriv = dwc_otg_urb; -- if (!dwc_otg_urb && urb->number_of_packets) -- return -ENOMEM; -+ urb->hcpriv = dwc_otg_urb; -+ if (!dwc_otg_urb && urb->number_of_packets) -+ return -ENOMEM; - - dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe), - usb_pipeendpoint(urb->pipe), ep_type, -@@ -776,36 +776,35 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, - } - - #if USB_URB_EP_LINKING -- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); -+ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); - retval = usb_hcd_link_urb_to_ep(hcd, urb); -- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); -+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); - if (0 == retval) - #endif -- { -- retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, -- /*(dwc_otg_qh_t **)*/ -- ref_ep_hcpriv, -- mem_flags == GFP_ATOMIC ? 1 : 0); -- if (0 == retval) { -- if (alloc_bandwidth) { -- allocate_bus_bandwidth(hcd, -- dwc_otg_hcd_get_ep_bandwidth( -- dwc_otg_hcd, *ref_ep_hcpriv), -- urb); -- } -- } else { -+ { -+ retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, -+ /*(dwc_otg_qh_t **)*/ -+ ref_ep_hcpriv, -+ mem_flags == GFP_ATOMIC ? 1 : 0); -+ if (0 == retval) { -+ if (alloc_bandwidth) { -+ allocate_bus_bandwidth(hcd, -+ dwc_otg_hcd_get_ep_bandwidth( -+ dwc_otg_hcd, *ref_ep_hcpriv), -+ urb); -+ } -+ } else { - #if USB_URB_EP_LINKING - dwc_irqflags_t irqflags; -- DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval); -- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); -- usb_hcd_unlink_urb_from_ep(hcd, urb); -- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); -+ DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval); -+ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); -+ usb_hcd_unlink_urb_from_ep(hcd, urb); -+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); - #endif -- if (retval == -DWC_E_NO_DEVICE) { -- retval = -ENODEV; -- } -- } -- } -+ if (retval == -DWC_E_NO_DEVICE) -+ retval = -ENODEV; -+ } -+ } - return retval; - } - --- -1.9.3 - - -From b1d7b4c3894f69321d9aa21d0ca6082ab472f944 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Thu, 18 Jul 2013 17:07:26 +0100 -Subject: [PATCH 044/124] dwc_otg: prevent OOPSes during device disconnects - -The dwc_otg_urb_enqueue function is thread-unsafe. In particular the -access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and -friends does not occur within a critical section and so if a device -was unplugged during activity there was a high chance that the -usbcore hub_thread would try to disable the endpoint with partially- -formed entries in the URB queue. This would result in BUG() or null -pointer dereferences. - -Fix so that access of urb->hcpriv, enqueuing to the hardware and -adding to usbcore endpoint URB lists is contained within a single -critical section. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 3 --- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 14 +++++--------- - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 6 +----- - 3 files changed, 6 insertions(+), 17 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index ec00b13..aeabbb1 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -464,7 +464,6 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle, - int atomic_alloc) - { -- dwc_irqflags_t flags; - int retval = 0; - uint8_t needs_scheduling = 0; - dwc_otg_transaction_type_e tr_type; -@@ -515,12 +514,10 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - } - - if(needs_scheduling) { -- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); - tr_type = dwc_otg_hcd_select_transactions(hcd); - if (tr_type != DWC_OTG_TRANSACTION_NONE) { - dwc_otg_hcd_queue_transactions(hcd, tr_type); - } -- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); - } - return retval; - } -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index 315c803..87e517d 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -679,9 +679,7 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) - struct usb_host_endpoint *ep = urb->ep; - #endif --#if USB_URB_EP_LINKING - dwc_irqflags_t irqflags; --#endif - void **ref_ep_hcpriv = &ep->hcpriv; - dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); - dwc_otg_hcd_urb_t *dwc_otg_urb; -@@ -733,7 +731,6 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, - if(dwc_otg_urb == NULL) - return -ENOMEM; - -- urb->hcpriv = dwc_otg_urb; - if (!dwc_otg_urb && urb->number_of_packets) - return -ENOMEM; - -@@ -775,10 +772,10 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, - iso_frame_desc[i].length); - } - --#if USB_URB_EP_LINKING - DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); -+ urb->hcpriv = dwc_otg_urb; -+#if USB_URB_EP_LINKING - retval = usb_hcd_link_urb_to_ep(hcd, urb); -- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); - if (0 == retval) - #endif - { -@@ -794,17 +791,16 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, - urb); - } - } else { --#if USB_URB_EP_LINKING -- dwc_irqflags_t irqflags; - DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval); -- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); -+#if USB_URB_EP_LINKING - usb_hcd_unlink_urb_from_ep(hcd, urb); -- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); - #endif -+ urb->hcpriv = NULL; - if (retval == -DWC_E_NO_DEVICE) - retval = -ENODEV; - } - } -+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); - return retval; - } - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index 7b92025..db95851 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -919,6 +919,7 @@ void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb) - * QH to place the QTD into. If it does not find a QH, then it will create a - * new QH. If the QH to which the QTD is added is not currently scheduled, it - * is placed into the proper schedule based on its EP type. -+ * HCD lock must be held and interrupts must be disabled on entry - * - * @param[in] qtd The QTD to add - * @param[in] hcd The DWC HCD structure -@@ -931,8 +932,6 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, - dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc) - { - int retval = 0; -- dwc_irqflags_t flags; -- - dwc_otg_hcd_urb_t *urb = qtd->urb; - - /* -@@ -946,15 +945,12 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, - goto done; - } - } -- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); - retval = dwc_otg_hcd_qh_add(hcd, *qh); - if (retval == 0) { - DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd, - qtd_list_entry); - qtd->qh = *qh; - } -- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); -- - done: - - return retval; --- -1.9.3 - - -From d3fd11c64dfc90cad3c3a10be5e72034351647e2 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Mon, 22 Jul 2013 14:08:26 +0100 -Subject: [PATCH 045/124] dwc_otg: prevent BUG() in TT allocation if hub - address is > 16 - -A fixed-size array is used to track TT allocation. This was -previously set to 16 which caused a crash because -dwc_otg_hcd_allocate_port would read past the end of the array. - -This was hit if a hub was plugged in which enumerated as addr > 16, -due to previous device resets or unplugs. - -Also add #ifdef FIQ_DEBUG around hcd->hub_port_alloc[], which grows -to a large size if 128 hub addresses are supported. This field is -for debug only for tracking which frame an allocate happened in. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 7 ++++++- - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 6 ++++-- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 3 ++- - 3 files changed, 12 insertions(+), 4 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index aeabbb1..f743702 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -983,7 +983,9 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) - hcd->periodic_qh_count = 0; - - DWC_MEMSET(hcd->hub_port, 0, sizeof(hcd->hub_port)); -+#ifdef FIQ_DEBUG - DWC_MEMSET(hcd->hub_port_alloc, -1, sizeof(hcd->hub_port_alloc)); -+#endif - - out: - return retval; -@@ -1317,7 +1319,9 @@ int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) - qh->skip_count = 0; - hcd->hub_port[hub_addr] |= 1 << port_addr; - fiq_print(FIQDBG_PORTHUB, "H%dP%d:A %d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); -+#ifdef FIQ_DEBUG - hcd->hub_port_alloc[hub_addr * 16 + port_addr] = dwc_otg_hcd_get_frame_number(hcd); -+#endif - return 0; - } - } -@@ -1331,8 +1335,9 @@ void dwc_otg_hcd_release_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) - hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); - - hcd->hub_port[hub_addr] &= ~(1 << port_addr); -+#ifdef FIQ_DEBUG - hcd->hub_port_alloc[hub_addr * 16 + port_addr] = -1; -- -+#endif - fiq_print(FIQDBG_PORTHUB, "H%dP%d:RO%d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); - - } -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -index de1ccb1..0007fa1 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -@@ -577,8 +577,10 @@ struct dwc_otg_hcd { - uint32_t *frame_list; - - /** Hub - Port assignment */ -- int hub_port[16]; -- int hub_port_alloc[256]; -+ int hub_port[128]; -+#ifdef FIQ_DEBUG -+ int hub_port_alloc[2048]; -+#endif - - /** Frame List DMA address */ - dma_addr_t frame_list_dma; -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 083b1c3..c76910d 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -1419,8 +1419,9 @@ static void release_channel(dwc_otg_hcd_t * hcd, - } - - hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); -+#ifdef FIQ_DEBUG - hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; -- -+#endif - fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); - } - --- -1.9.3 - - -From 39e288e785c25ddf86ea11799b996df8989e00b2 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Tue, 23 Jul 2013 14:15:32 +0100 -Subject: [PATCH 046/124] dwc_otg: make channel halts with unknown state less - damaging - -If the IRQ received a channel halt interrupt through the FIQ -with no other bits set, the IRQ would not release the host -channel and never complete the URB. - -Add catchall handling to treat as a transaction error and retry. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index c76910d..5fd8613 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -2578,12 +2578,24 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + if (hcint.b.xfercomp) { + /** @todo This is here because of a possible hardware bug. Spec +@@ -1937,6 +2538,8 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + handle_hc_babble_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.frmovrun) { + handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.datatglerr) { ++ handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd); + } else if (!out_nak_enh) { + if (hcint.b.nyet) { + /* +@@ -1986,12 +2589,24 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, DWC_READ_REG32(&hcd-> core_if->core_global_regs-> gintsts)); @@ -96860,327 +95606,34 @@ index c76910d..5fd8613 100644 } } --- -1.9.3 - - -From c370085d946fe3b68e4e1463565c71f0c6884f14 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Tue, 30 Jul 2013 09:58:48 +0100 -Subject: [PATCH 047/124] dwc_otg: fiq_split: use TTs with more granularity - -This fixes certain issues with split transaction scheduling. - -- Isochronous multi-packet OUT transactions now hog the TT until - they are completed - this prevents hubs aborting transactions - if they get a periodic start-split out-of-order -- Don't perform TT allocation on non-periodic endpoints - this - allows simultaneous use of the TT's bulk/control and periodic - transaction buffers - -This commit will mainly affect USB audio playback. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 26 +++++++++++++------------- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 20 ++++++++++++++++---- - 2 files changed, 29 insertions(+), 17 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index f743702..489b765 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -1356,6 +1356,7 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) +@@ -2009,13 +2624,15 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, +- dwc_otg_qtd_t * qtd) ++ dwc_otg_qtd_t * qtd, ++ hcint_data_t hcint, ++ hcintmsk_data_t hcintmsk) { - dwc_list_link_t *qh_ptr; - dwc_otg_qh_t *qh; -+ dwc_otg_qtd_t *qtd; - int num_channels; - dwc_irqflags_t flags; - dwc_spinlock_t *channel_lock = hcd->channel_lock; -@@ -1379,11 +1380,18 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " + "Channel Halted--\n", hc->hc_num); - qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - -- if(qh->do_split && dwc_otg_hcd_allocate_port(hcd, qh)) -- { -- qh_ptr = DWC_LIST_NEXT(qh_ptr); -- g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); -- continue; -+ if(qh->do_split) { -+ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); -+ if(!(qh->ep_type == UE_ISOCHRONOUS && -+ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID || -+ qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))) { -+ if(dwc_otg_hcd_allocate_port(hcd, qh)) -+ { -+ qh_ptr = DWC_LIST_NEXT(qh_ptr); -+ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); -+ continue; -+ } -+ } - } - - if (microframe_schedule) { -@@ -1451,18 +1459,10 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - } - } - -- if (qh->do_split && dwc_otg_hcd_allocate_port(hcd, qh)) -- { -- g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); -- qh_ptr = DWC_LIST_NEXT(qh_ptr); -- continue; -- } -- - if (microframe_schedule) { - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - if (hcd->available_host_channels < 1) { - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); -- if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh); - break; - } - hcd->available_host_channels--; -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 5fd8613..a959a49 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -1328,10 +1328,20 @@ static void release_channel(dwc_otg_hcd_t * hcd, - #ifdef FIQ_DEBUG - int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0; - #endif -+ int hog_port = 0; - - DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", - __func__, hc->hc_num, halt_status, hc->xfer_len); - -+ if(fiq_split_enable && hc->do_split) { -+ if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) { -+ if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID || -+ hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) { -+ hog_port = 1; -+ } -+ } -+ } -+ - switch (halt_status) { - case DWC_OTG_HC_XFER_URB_COMPLETE: - free_qtd = 1; -@@ -1417,12 +1427,14 @@ static void release_channel(dwc_otg_hcd_t * hcd, - fiq_print(FIQDBG_ERR, "PRTNOTAL"); - //BUG(); - } -- -- hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); -+ if(!hog_port && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC || -+ hc->ep_type == DWC_OTG_EP_TYPE_INTR)) { -+ hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); - #ifdef FIQ_DEBUG -- hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; -+ hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; - #endif -- fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); -+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); -+ } - } - - /* Try to queue more transfers now that there's a free channel. */ --- -1.9.3 - - -From e48aaa150b75c5fd805ef9ffe3c9f0015c039efe Mon Sep 17 00:00:00 2001 -From: P33M -Date: Fri, 2 Aug 2013 10:04:18 +0100 -Subject: [PATCH 048/124] dwc_otg: fix potential sleep while atomic during urb - enqueue - -Fixes a regression introduced with eb1b482a. Kmalloc called from -dwc_otg_hcd_qtd_add / dwc_otg_hcd_qtd_create did not always have -the GPF_ATOMIC flag set. Force this flag when inside the larger -critical section. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index 87e517d..88c0544 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -781,8 +781,7 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, - { - retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, - /*(dwc_otg_qh_t **)*/ -- ref_ep_hcpriv, -- mem_flags == GFP_ATOMIC ? 1 : 0); -+ ref_ep_hcpriv, 1); - if (0 == retval) { - if (alloc_bandwidth) { - allocate_bus_bandwidth(hcd, --- -1.9.3 - - -From 4984b8762f5944656866e4a2cacffeb5a1071614 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Mon, 5 Aug 2013 11:42:12 +0100 -Subject: [PATCH 049/124] dwc_otg: make fiq_split_enable imply fiq_fix_enable - -Failing to set up the FIQ correctly would result in -"IRQ 32: nobody cared" errors in dmesg. ---- - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index 176dc14..f06c3d22 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -1070,6 +1070,12 @@ static int __init dwc_otg_driver_init(void) + if (hcd->core_if->dma_enable) { +- handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd); ++ handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd, hcint, hcintmsk); + } else { + #ifdef DEBUG + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) { +@@ -2032,7 +2649,7 @@ static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, + int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) + { int retval = 0; - int error; - struct device_driver *drv; -+ -+ if(fiq_split_enable && !fiq_fix_enable) { -+ printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n"); -+ fiq_fix_enable = 1; -+ } -+ - printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name, - DWC_DRIVER_VERSION, - #ifdef LM_INTERFACE --- -1.9.3 - - -From d4426fec1f1ed4e1e584a83571a58155236f8e3d Mon Sep 17 00:00:00 2001 -From: P33M -Date: Mon, 5 Aug 2013 11:47:12 +0100 -Subject: [PATCH 050/124] dwc_otg: prevent crashes on host port disconnects - -Fix several issues resulting in crashes or inconsistent state -if a Model A root port was disconnected. - -- Clean up queue heads properly in kill_urbs_in_qh_list by - removing the empty QHs from the schedule lists -- Set the halt status properly to prevent IRQ handlers from - using freed memory -- Add fiq_split related cleanup for saved registers -- Make microframe scheduling reclaim host channels if - active during a disconnect -- Abort URBs with -ESHUTDOWN status response, informing - device drivers so they respond in a more correct fashion - and don't try to resubmit URBs -- Prevent IRQ handlers from attempting to handle channel - interrupts if the associated URB was dequeued (and the - driver state was cleared) ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 44 ++++++++++++++++++++++++---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 7 +++++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 3 ++ - 3 files changed, 48 insertions(+), 6 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 489b765..1904f6a 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -59,6 +59,11 @@ static int last_sel_trans_num_avail_hc_at_end = 0; - - extern int g_next_sched_frame, g_np_count, g_np_sent; - -+extern haint_data_t haint_saved; -+extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; -+extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; -+extern gintsts_data_t ginsts_saved; -+ - dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) - { - return DWC_ALLOC(sizeof(dwc_otg_hcd_t)); -@@ -168,31 +173,43 @@ static void del_timers(dwc_otg_hcd_t * hcd) - - /** - * Processes all the URBs in a single list of QHs. Completes them with -- * -ETIMEDOUT and frees the QTD. -+ * -ESHUTDOWN and frees the QTD. - */ - static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) - { -- dwc_list_link_t *qh_item; -+ dwc_list_link_t *qh_item, *qh_tmp; - dwc_otg_qh_t *qh; - dwc_otg_qtd_t *qtd, *qtd_tmp; - -- DWC_LIST_FOREACH(qh_item, qh_list) { -+ DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) { - qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry); - DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, - &qh->qtd_list, qtd_list_entry) { - qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); - if (qtd->urb != NULL) { - hcd->fops->complete(hcd, qtd->urb->priv, -- qtd->urb, -DWC_E_TIMEOUT); -+ qtd->urb, -DWC_E_SHUTDOWN); - dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); - } - - } -+ if(qh->channel) { -+ /* Using hcchar.chen == 1 is not a reliable test. -+ * It is possible that the channel has already halted -+ * but not yet been through the IRQ handler. -+ */ -+ dwc_otg_hc_halt(hcd->core_if, qh->channel, -+ DWC_OTG_HC_XFER_URB_DEQUEUE); -+ if(microframe_schedule) -+ hcd->available_host_channels++; -+ qh->channel = NULL; -+ } -+ dwc_otg_hcd_qh_remove(hcd, qh); - } - } - - /** -- * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic -+ * Responds with an error status of ESHUTDOWN to all URBs in the non-periodic - * and periodic schedules. The QTD associated with each URB is removed from - * the schedule and freed. This function may be called when a disconnect is - * detected or when the HCD is being stopped. -@@ -278,7 +295,8 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) - */ - dwc_otg_hcd->flags.b.port_connect_status_change = 1; - dwc_otg_hcd->flags.b.port_connect_status = 0; -- -+ if(fiq_fix_enable) -+ local_fiq_disable(); - /* - * Shutdown any transfers in process by clearing the Tx FIFO Empty - * interrupt mask and status bits and disabling subsequent host -@@ -374,8 +392,22 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) - channel->qh = NULL; - } - } -+ if(fiq_split_enable) { -+ for(i=0; i < 128; i++) { -+ dwc_otg_hcd->hub_port[i] = 0; -+ } -+ haint_saved.d32 = 0; -+ for(i=0; i < MAX_EPS_CHANNELS; i++) { -+ hcint_saved[i].d32 = 0; -+ hcintmsk_saved[i].d32 = 0; -+ } -+ } -+ - } - -+ if(fiq_fix_enable) -+ local_fiq_enable(); -+ - if (dwc_otg_hcd->fops->disconnect) { - dwc_otg_hcd->fops->disconnect(dwc_otg_hcd); - } -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index a959a49..3a549a1 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -2660,6 +2660,13 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) +- hcint_data_t hcint; ++ hcint_data_t hcint, hcint_orig; + hcintmsk_data_t hcintmsk; + dwc_hc_t *hc; + dwc_otg_hc_regs_t *hc_regs; +@@ -2042,15 +2659,33 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) hc = dwc_otg_hcd->hc_ptr_array[num]; hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num]; @@ -97194,11 +95647,114 @@ index a959a49..3a549a1 100644 qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ hcint_orig = hcint; + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); + DWC_DEBUGPL(DBG_HCDV, + " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", + hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); + hcint.d32 = hcint.d32 & hcintmsk.d32; + ++ if(fiq_split_enable) ++ { ++ // replace with the saved interrupts from the fiq handler ++ local_fiq_disable(); ++ hcint_orig.d32 = hcint_saved[num].d32; ++ hcint.d32 = hcint_orig.d32 & hcintmsk_saved[num].d32; ++ hcint_saved[num].d32 = 0; ++ local_fiq_enable(); ++ } ++ + if (!dwc_otg_hcd->core_if->dma_enable) { + if (hcint.b.chhltd && hcint.d32 != 0x2) { + hcint.b.chhltd = 0; +@@ -2068,7 +2703,7 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) + hcint.b.nyet = 0; + } + if (hcint.b.chhltd) { +- retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd, hcint_orig, hcintmsk_saved[num]); + } + if (hcint.b.ahberr) { + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd); +@@ -2080,7 +2715,8 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) + retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.ack) { +- retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ if(!hcint.b.chhltd) ++ retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.nyet) { + retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd); +@@ -2102,5 +2738,4 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) + + return retval; + } +- + #endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index 88c0544..ae4271a 100644 +index e4787f5..ee8eec9 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -309,6 +309,9 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, +@@ -1,3 +1,4 @@ ++ + /* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $ + * $Revision: #20 $ +@@ -50,6 +51,7 @@ + #include + #include + #include ++#include + #include + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + #include <../drivers/usb/core/hcd.h> +@@ -67,6 +69,8 @@ + #include "dwc_otg_dbg.h" + #include "dwc_otg_driver.h" + #include "dwc_otg_hcd.h" ++#include "dwc_otg_mphi_fix.h" ++ + /** + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is + * qualified with its direction (possible 32 endpoints per device). +@@ -76,6 +80,8 @@ + + static const char dwc_otg_hcd_name[] = "dwc_otg_hcd"; + ++extern bool fiq_fix_enable; ++ + /** @name Linux HC Driver API Functions */ + /** @{ */ + /* manage i/o requests, device state */ +@@ -259,13 +265,15 @@ static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw, + + /** + * Sets the final status of an URB and returns it to the device driver. Any +- * required cleanup of the URB is performed. ++ * required cleanup of the URB is performed. The HCD lock should be held on ++ * entry. + */ + static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status) + { + struct urb *urb = (struct urb *)urb_handle; +- ++ urb_tq_entry_t *new_entry; ++ int rc = 0; + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n", + __func__, urb, usb_pipedevice(urb->pipe), +@@ -279,7 +287,7 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, + } + } + } +- ++ new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t)); + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb); + /* Convert status value. */ + switch (status) { +@@ -301,6 +309,9 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, case -DWC_E_OVERFLOW: status = -EOVERFLOW; break; @@ -97208,35 +95764,203 @@ index 88c0544..ae4271a 100644 default: if (status) { DWC_PRINTF("Uknown urb status %d\n", status); --- -1.9.3 - - -From 95cd6869b44fa2aa54db40b21dbd54f2a3d3868a Mon Sep 17 00:00:00 2001 -From: P33M -Date: Mon, 5 Aug 2013 13:17:58 +0100 -Subject: [PATCH 051/124] dwc_otg: prevent leaking URBs during enqueue - -A dwc_otg_urb would get leaked if the HCD enqueue function -failed for any reason. Free the URB at the appropriate points. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index ae4271a..ee8eec9 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -797,11 +797,19 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, - #if USB_URB_EP_LINKING - usb_hcd_unlink_urb_from_ep(hcd, urb); - #endif -+ DWC_FREE(dwc_otg_urb); - urb->hcpriv = NULL; - if (retval == -DWC_E_NO_DEVICE) - retval = -ENODEV; - } +@@ -342,18 +353,33 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, } + + DWC_FREE(dwc_otg_urb); +- ++ if (!new_entry) { ++ DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n"); ++ urb->status = -EPROTO; ++ /* don't schedule the tasklet - ++ * directly return the packet here with error. */ + #if USB_URB_EP_LINKING +- usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); ++ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); + #endif +- DWC_SPINUNLOCK(hcd->lock); + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) +- usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); ++ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); + #else +- usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status); ++ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); + #endif +- DWC_SPINLOCK(hcd->lock); +- ++ } else { ++ new_entry->urb = urb; ++#if USB_URB_EP_LINKING ++ rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); ++ if(0 == rc) { ++ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); ++ } ++#endif ++ if(0 == rc) { ++ DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry, ++ urb_tq_entries); ++ DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet); ++ } ++ } + return 0; + } + +@@ -366,6 +392,16 @@ static struct dwc_otg_hcd_function_ops hcd_fops = { + .get_b_hnp_enable = _get_b_hnp_enable, + }; + ++static struct fiq_handler fh = { ++ .name = "usb_fiq", ++}; ++struct fiq_stack_s { ++ int magic1; ++ uint8_t stack[2048]; ++ int magic2; ++} fiq_stack; ++ ++extern mphi_regs_t c_mphi_regs; + /** + * Initializes the HCD. This function allocates memory for and initializes the + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the +@@ -379,6 +415,7 @@ int hcd_init(dwc_bus_dev_t *_dev) + dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev); + int retval = 0; + u64 dmamask; ++ struct pt_regs regs; + + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev); + +@@ -396,6 +433,20 @@ int hcd_init(dwc_bus_dev_t *_dev) + pci_set_consistent_dma_mask(_dev, dmamask); + #endif + ++ if (fiq_fix_enable) ++ { ++ // Set up fiq ++ claim_fiq(&fh); ++ set_fiq_handler(__FIQ_Branch, 4); ++ memset(®s,0,sizeof(regs)); ++ regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq; ++ regs.ARM_r9 = (long)0; ++ regs.ARM_sp = (long)fiq_stack.stack + sizeof(fiq_stack.stack) - 4; ++ set_fiq_regs(®s); ++ fiq_stack.magic1 = 0xdeadbeef; ++ fiq_stack.magic2 = 0xaa995566; ++ } ++ + /* + * Allocate memory for the base HCD plus the DWC OTG HCD. + * Initialize the base HCD. +@@ -415,6 +466,30 @@ int hcd_init(dwc_bus_dev_t *_dev) + + hcd->regs = otg_dev->os_dep.base; + ++ if (fiq_fix_enable) ++ { ++ volatile extern void *dwc_regs_base; ++ ++ //Set the mphi periph to the required registers ++ c_mphi_regs.base = otg_dev->os_dep.mphi_base; ++ c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; ++ c_mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28; ++ c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; ++ c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; ++ ++ dwc_regs_base = otg_dev->os_dep.base; ++ ++ //Enable mphi peripheral ++ writel((1<<31),c_mphi_regs.ctrl); ++#ifdef DEBUG ++ if (readl(c_mphi_regs.ctrl) & 0x80000000) ++ DWC_DEBUGPL(DBG_USER, "MPHI periph has been enabled\n"); ++ else ++ DWC_DEBUGPL(DBG_USER, "MPHI periph has NOT been enabled\n"); ++#endif ++ // Enable FIQ interrupt from USB peripheral ++ enable_fiq(INTERRUPT_VC_USB); ++ } + /* Initialize the DWC OTG HCD. */ + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd(); + if (!dwc_otg_hcd) { +@@ -607,9 +682,7 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) + struct usb_host_endpoint *ep = urb->ep; + #endif +-#if USB_URB_EP_LINKING + dwc_irqflags_t irqflags; +-#endif + void **ref_ep_hcpriv = &ep->hcpriv; + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + dwc_otg_hcd_urb_t *dwc_otg_urb; +@@ -661,9 +734,8 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, + if(dwc_otg_urb == NULL) + return -ENOMEM; + +- urb->hcpriv = dwc_otg_urb; +- if (!dwc_otg_urb && urb->number_of_packets) +- return -ENOMEM; ++ if (!dwc_otg_urb && urb->number_of_packets) ++ return -ENOMEM; + + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe), + usb_pipeendpoint(urb->pipe), ep_type, +@@ -703,37 +775,42 @@ static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, + iso_frame_desc[i].length); + } + ++ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); ++ urb->hcpriv = dwc_otg_urb; + #if USB_URB_EP_LINKING +- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); + retval = usb_hcd_link_urb_to_ep(hcd, urb); +- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); + if (0 == retval) + #endif +- { +- retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, +- /*(dwc_otg_qh_t **)*/ +- ref_ep_hcpriv, +- mem_flags == GFP_ATOMIC ? 1 : 0); +- if (0 == retval) { +- if (alloc_bandwidth) { +- allocate_bus_bandwidth(hcd, +- dwc_otg_hcd_get_ep_bandwidth( +- dwc_otg_hcd, *ref_ep_hcpriv), +- urb); +- } +- } else { ++ { ++ retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, ++ /*(dwc_otg_qh_t **)*/ ++ ref_ep_hcpriv, 1); ++ if (0 == retval) { ++ if (alloc_bandwidth) { ++ allocate_bus_bandwidth(hcd, ++ dwc_otg_hcd_get_ep_bandwidth( ++ dwc_otg_hcd, *ref_ep_hcpriv), ++ urb); ++ } ++ } else { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval); + #if USB_URB_EP_LINKING +- dwc_irqflags_t irqflags; +- DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval); +- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); +- usb_hcd_unlink_urb_from_ep(hcd, urb); +- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); ++ usb_hcd_unlink_urb_from_ep(hcd, urb); + #endif +- if (retval == -DWC_E_NO_DEVICE) { +- retval = -ENODEV; +- } +- } +- } ++ DWC_FREE(dwc_otg_urb); ++ urb->hcpriv = NULL; ++ if (retval == -DWC_E_NO_DEVICE) ++ retval = -ENODEV; ++ } ++ } +#if USB_URB_EP_LINKING + else + { @@ -97244,127 +95968,5292 @@ index ae4271a..ee8eec9 100644 + urb->hcpriv = NULL; + } +#endif - DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); ++ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); return retval; } --- -1.9.3 - - -From 4f9e44d8d3491d2878384a41b6addb19a129a78b Mon Sep 17 00:00:00 2001 -From: P33M -Date: Fri, 20 Sep 2013 16:08:27 +0100 -Subject: [PATCH 052/124] dwc_otg: Enable NAK holdoff for control split - transactions - -Certain low-speed devices take a very long time to complete a -data or status stage of a control transaction, producing NAK -responses until they complete internal processing - the USB2.0 -spec limit is up to 500mS. This causes the same type of interrupt -storm as seen with USB-serial dongles prior to c8edb238. - -In certain circumstances, usually while booting, this interrupt -storm could cause SD card timeouts. ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 3a549a1..f8dc4be 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -1857,8 +1857,7 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, - */ - switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { - case UE_BULK: -- //case UE_INTERRUPT: -- //case UE_CONTROL: -+ case UE_CONTROL: - if (nak_holdoff_enable) - hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd); - } --- -1.9.3 - - -From 18359848bbffc54db51c20795b4d9e48f8f07eef Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 20 Sep 2013 19:07:56 +0100 -Subject: [PATCH 053/124] dwc_otg: Fix for occasional lockup on boot when doing - a USB reset - ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index f8dc4be..64d33a5 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -742,8 +742,8 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) + +@@ -777,6 +854,8 @@ static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) + usb_hcd_unlink_urb_from_ep(hcd, urb); + #endif + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags); ++ ++ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) + usb_hcd_giveback_urb(hcd, urb); + #else +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c +index 9761566..db95851 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c +@@ -41,6 +41,7 @@ + + #include "dwc_otg_hcd.h" + #include "dwc_otg_regs.h" ++#include "dwc_otg_mphi_fix.h" + + extern bool microframe_schedule; + +@@ -181,6 +182,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) + if (microframe_schedule) + qh->speed = dev_speed; + ++ qh->nak_frame = 0xffff; + + if (((dev_speed == USB_SPEED_LOW) || + (dev_speed == USB_SPEED_FULL)) && +@@ -190,6 +192,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) + dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr, + hub_port); + qh->do_split = 1; ++ qh->skip_count = 0; } - /* Clear interrupt */ -- //gintsts.b.sofintr = 1; -- //DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); -+ gintsts.b.sofintr = 1; -+ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); - - return 1; + if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) { +@@ -572,6 +575,9 @@ static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + return status; } + ++ ++extern int g_next_sched_frame, g_np_count, g_np_sent; ++ + /** + * Schedules an interrupt or isochronous transfer in the periodic schedule. + * +@@ -630,8 +636,13 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry); + } + else { +- /* Always start in the inactive schedule. */ +- DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry); ++ if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, g_next_sched_frame)) ++ { ++ g_next_sched_frame = qh->sched_frame; ++ ++ } ++ /* Always start in the inactive schedule. */ ++ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry); + } + + if (!microframe_schedule) { +@@ -645,6 +656,7 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + return status; + } + ++ + /** + * This function adds a QH to either the non periodic or periodic schedule if + * it is not already in the schedule. If the QH is already in the schedule, no +@@ -667,6 +679,7 @@ int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + /* Always start in the inactive schedule. */ + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive, + &qh->qh_list_entry); ++ g_np_count++; + } else { + status = schedule_periodic(hcd, qh); + if ( !hcd->periodic_qh_count ) { +@@ -726,6 +739,9 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + hcd->non_periodic_qh_ptr->next; + } + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); ++ ++ // If we've removed the last non-periodic entry then there are none left! ++ g_np_count = g_np_sent; + } else { + deschedule_periodic(hcd, qh); + hcd->periodic_qh_count--; +@@ -754,6 +770,24 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, + int sched_next_periodic_split) + { + if (dwc_qh_is_non_per(qh)) { ++ ++ dwc_otg_qh_t *qh_tmp; ++ dwc_list_link_t *qh_list; ++ DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) ++ { ++ qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); ++ if(qh_tmp == qh) ++ { ++ /* ++ * FIQ is being disabled because this one nevers gets a np_count increment ++ * This is still not absolutely correct, but it should fix itself with ++ * just an unnecessary extra interrupt ++ */ ++ g_np_sent = g_np_count; ++ } ++ } ++ ++ + dwc_otg_hcd_qh_remove(hcd, qh); + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { + /* Add back to inactive non-periodic schedule. */ +@@ -767,6 +801,7 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, + if (sched_next_periodic_split) { + + qh->sched_frame = frame_number; ++ + if (dwc_frame_num_le(frame_number, + dwc_frame_num_inc + (qh->start_split_frame, +@@ -815,6 +850,11 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, + &qh->qh_list_entry); + } else { ++ if(!dwc_frame_num_le(g_next_sched_frame, qh->sched_frame)) ++ { ++ g_next_sched_frame = qh->sched_frame; ++ } ++ + DWC_LIST_MOVE_HEAD + (&hcd->periodic_sched_inactive, + &qh->qh_list_entry); +@@ -879,6 +919,7 @@ void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb) + * QH to place the QTD into. If it does not find a QH, then it will create a + * new QH. If the QH to which the QTD is added is not currently scheduled, it + * is placed into the proper schedule based on its EP type. ++ * HCD lock must be held and interrupts must be disabled on entry + * + * @param[in] qtd The QTD to add + * @param[in] hcd The DWC HCD structure +@@ -891,8 +932,6 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, + dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc) + { + int retval = 0; +- dwc_irqflags_t flags; +- + dwc_otg_hcd_urb_t *urb = qtd->urb; + + /* +@@ -902,18 +941,16 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, + if (*qh == NULL) { + *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc); + if (*qh == NULL) { +- retval = -1; ++ retval = -DWC_E_NO_MEMORY; + goto done; + } + } +- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + retval = dwc_otg_hcd_qh_add(hcd, *qh); + if (retval == 0) { + DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd, + qtd_list_entry); ++ qtd->qh = *qh; + } +- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); +- + done: + + return retval; +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c +new file mode 100755 +index 0000000..50b94a8 +--- /dev/null ++++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c +@@ -0,0 +1,113 @@ ++#include "dwc_otg_regs.h" ++#include "dwc_otg_dbg.h" ++ ++void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name) ++{ ++ DWC_DEBUGPL(DBG_USER, "*** Debugging from within the %s function: ***\n" ++ "curmode: %1i Modemismatch: %1i otgintr: %1i sofintr: %1i\n" ++ "rxstsqlvl: %1i nptxfempty : %1i ginnakeff: %1i goutnakeff: %1i\n" ++ "ulpickint: %1i i2cintr: %1i erlysuspend:%1i usbsuspend: %1i\n" ++ "usbreset: %1i enumdone: %1i isooutdrop: %1i eopframe: %1i\n" ++ "restoredone: %1i epmismatch: %1i inepint: %1i outepintr: %1i\n" ++ "incomplisoin:%1i incomplisoout:%1i fetsusp: %1i resetdet: %1i\n" ++ "portintr: %1i hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i\n" ++ "conidstschng:%1i disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", ++ function_name, ++ gintsts.b.curmode, ++ gintsts.b.modemismatch, ++ gintsts.b.otgintr, ++ gintsts.b.sofintr, ++ gintsts.b.rxstsqlvl, ++ gintsts.b.nptxfempty, ++ gintsts.b.ginnakeff, ++ gintsts.b.goutnakeff, ++ gintsts.b.ulpickint, ++ gintsts.b.i2cintr, ++ gintsts.b.erlysuspend, ++ gintsts.b.usbsuspend, ++ gintsts.b.usbreset, ++ gintsts.b.enumdone, ++ gintsts.b.isooutdrop, ++ gintsts.b.eopframe, ++ gintsts.b.restoredone, ++ gintsts.b.epmismatch, ++ gintsts.b.inepint, ++ gintsts.b.outepintr, ++ gintsts.b.incomplisoin, ++ gintsts.b.incomplisoout, ++ gintsts.b.fetsusp, ++ gintsts.b.resetdet, ++ gintsts.b.portintr, ++ gintsts.b.hcintr, ++ gintsts.b.ptxfempty, ++ gintsts.b.lpmtranrcvd, ++ gintsts.b.conidstschng, ++ gintsts.b.disconnect, ++ gintsts.b.sessreqintr, ++ gintsts.b.wkupintr); ++ return; ++} ++ ++void dwc_debug_core_int_mask(gintmsk_data_t gintmsk, const char* function_name) ++{ ++ DWC_DEBUGPL(DBG_USER, "Interrupt Mask status (called from %s) :\n" ++ "modemismatch: %1i otgintr: %1i sofintr: %1i rxstsqlvl: %1i\n" ++ "nptxfempty: %1i ginnakeff: %1i goutnakeff: %1i ulpickint: %1i\n" ++ "i2cintr: %1i erlysuspend:%1i usbsuspend: %1i usbreset: %1i\n" ++ "enumdone: %1i isooutdrop: %1i eopframe: %1i restoredone: %1i\n" ++ "epmismatch: %1i inepintr: %1i outepintr: %1i incomplisoin:%1i\n" ++ "incomplisoout:%1i fetsusp: %1i resetdet: %1i portintr: %1i\n" ++ "hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i conidstschng:%1i\n" ++ "disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", ++ function_name, ++ gintmsk.b.modemismatch, ++ gintmsk.b.otgintr, ++ gintmsk.b.sofintr, ++ gintmsk.b.rxstsqlvl, ++ gintmsk.b.nptxfempty, ++ gintmsk.b.ginnakeff, ++ gintmsk.b.goutnakeff, ++ gintmsk.b.ulpickint, ++ gintmsk.b.i2cintr, ++ gintmsk.b.erlysuspend, ++ gintmsk.b.usbsuspend, ++ gintmsk.b.usbreset, ++ gintmsk.b.enumdone, ++ gintmsk.b.isooutdrop, ++ gintmsk.b.eopframe, ++ gintmsk.b.restoredone, ++ gintmsk.b.epmismatch, ++ gintmsk.b.inepintr, ++ gintmsk.b.outepintr, ++ gintmsk.b.incomplisoin, ++ gintmsk.b.incomplisoout, ++ gintmsk.b.fetsusp, ++ gintmsk.b.resetdet, ++ gintmsk.b.portintr, ++ gintmsk.b.hcintr, ++ gintmsk.b.ptxfempty, ++ gintmsk.b.lpmtranrcvd, ++ gintmsk.b.conidstschng, ++ gintmsk.b.disconnect, ++ gintmsk.b.sessreqintr, ++ gintmsk.b.wkupintr); ++ return; ++} ++ ++void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name) ++{ ++ DWC_DEBUGPL(DBG_USER, "otg int register (from %s function):\n" ++ "sesenddet:%1i sesreqsucstschung:%2i hstnegsucstschng:%1i\n" ++ "hstnegdet:%1i adevtoutchng: %2i debdone: %1i\n" ++ "mvic: %1i\n", ++ function_name, ++ gotgint.b.sesenddet, ++ gotgint.b.sesreqsucstschng, ++ gotgint.b.hstnegsucstschng, ++ gotgint.b.hstnegdet, ++ gotgint.b.adevtoutchng, ++ gotgint.b.debdone, ++ gotgint.b.mvic); ++ ++ return; ++} +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h +new file mode 100755 +index 0000000..ca17379 +--- /dev/null ++++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h +@@ -0,0 +1,48 @@ ++#ifndef __DWC_OTG_MPHI_FIX_H__ ++#define __DWC_OTG_MPHI_FIX_H__ ++#define FIQ_WRITE(_addr_,_data_) (*(volatile uint32_t *) (_addr_) = (_data_)) ++#define FIQ_READ(_addr_) (*(volatile uint32_t *) (_addr_)) ++ ++typedef struct { ++ volatile void* base; ++ volatile void* ctrl; ++ volatile void* outdda; ++ volatile void* outddb; ++ volatile void* intstat; ++} mphi_regs_t; ++ ++void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name); ++void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name); ++void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); ++ ++extern gintsts_data_t gintsts_saved; ++ ++#ifdef DEBUG ++#define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__) ++#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) dwc_debug_core_int_mask(_arg_,__func__) ++#define DWC_DBG_PRINT_OTG_INT(_arg_) dwc_debug_otg_int(_arg_,__func__) ++ ++#else ++#define DWC_DBG_PRINT_CORE_INT(_arg_) ++#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) ++#define DWC_DBG_PRINT_OTG_INT(_arg_) ++ ++#endif ++ ++typedef enum { ++ FIQDBG_SCHED = (1 << 0), ++ FIQDBG_INT = (1 << 1), ++ FIQDBG_ERR = (1 << 2), ++ FIQDBG_PORTHUB = (1 << 3), ++} FIQDBG_T; ++ ++void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...); ++#ifdef FIQ_DEBUG ++#define fiq_print _fiq_print ++#else ++#define fiq_print(x, y, ...) ++#endif ++ ++extern bool fiq_fix_enable, nak_holdoff_enable, fiq_split_enable; ++ ++#endif +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h +index e46d9bb..6b2c7d0 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h ++++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h +@@ -97,6 +97,9 @@ typedef struct os_dependent { + /** Register offset for Diagnostic API */ + uint32_t reg_offset; + ++ /** Base address for MPHI peripheral */ ++ void *mphi_base; ++ + #ifdef LM_INTERFACE + struct lm_device *lmdev; + #elif defined(PCI_INTERFACE) +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c +index 1b1f83c..c8590b5 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c +@@ -4276,7 +4276,7 @@ do { \ + && (pcd->ep0state == EP0_OUT_DATA_PHASE)) + status.d32 = core_if->dev_if->out_desc_addr->status.d32; + if (pcd->ep0state == EP0_OUT_STATUS_PHASE) +- status.d32 = status.d32 = core_if->dev_if-> ++ status.d32 = core_if->dev_if-> + out_desc_addr->status.d32; + + if (status.b.sr) { -- 1.9.3 -From fde997c1334b92215d1931a42b43a411f0823a39 Mon Sep 17 00:00:00 2001 +From 664dcd42c98f7a75ea6d018907e1998e2771607e Mon Sep 17 00:00:00 2001 From: P33M -Date: Fri, 27 Sep 2013 14:42:24 +0100 -Subject: [PATCH 054/124] dwc_otg: Don't issue traffic to LS devices in FS mode +Date: Wed, 19 Mar 2014 12:58:23 +0000 +Subject: [PATCH 29/53] dwc_otg: fiq_fsm: Base commit for driver rewrite -Issuing low-speed packets when the root port is in full-speed mode -causes the root port to stop responding. Explicitly fail when -enqueuing URBs to a LS endpoint on a FS bus. +This commit removes the previous FIQ fixes entirely and adds fiq_fsm. + +This rewrite features much more complete support for split transactions +and takes into account several OTG hardware bugs. High-speed +isochronous transactions are also capable of being performed by fiq_fsm. + +All driver options have been removed and replaced with: + - dwc_otg.fiq_enable (bool) + - dwc_otg.fiq_fsm_enable (bool) + - dwc_otg.fiq_fsm_mask (bitmask) + - dwc_otg.nak_holdoff (unsigned int) + +Defaults are specified such that fiq_fsm behaves similarly to the +previously implemented FIQ fixes. + +fiq_fsm: Push error recovery into the FIQ when fiq_fsm is used + +If the transfer associated with a QTD failed due to a bus error, the HCD +would retry the transfer up to 3 times (implementing the USB2.0 +three-strikes retry in software). + +Due to the masking mechanism used by fiq_fsm, it is only possible to pass +a single interrupt through to the HCD per-transfer. + +In this instance host channels would fall off the radar because the error +reset would function, but the subsequent channel halt would be lost. + +Push the error count reset into the FIQ handler. + +fiq_fsm: Implement timeout mechanism + +For full-speed endpoints with a large packet size, interrupt latency +runs the risk of the FIQ starting a transaction too late in a full-speed +frame. If the device is still transmitting data when EOF2 for the +downstream frame occurs, the hub will disable the port. This change is +not reflected in the hub status endpoint and the device becomes +unresponsive. + +Prevent high-bandwidth transactions from being started too late in a +frame. The mechanism is not guaranteed: a combination of bit stuffing +and hub latency may still result in a device overrunning. + +fiq_fsm: fix bounce buffer utilisation for Isochronous OUT + +Multi-packet isochronous OUT transactions were subject to a few bounday +bugs. Fix them. + +Audio playback is now much more robust: however, an issue stands with +devices that have adaptive sinks - ALSA plays samples too fast. + +dwc_otg: Return full-speed frame numbers in HS mode + +The frame counter increments on every *microframe* in high-speed mode. +Most device drivers expect this number to be in full-speed frames - this +caused considerable confusion to e.g. snd_usb_audio which uses the +frame counter to estimate the number of samples played. + +fiq_fsm: save PID on completion of interrupt OUT transfers + +Also add edge case handling for interrupt transports. + +Note that for periodic split IN, data toggles are unimplemented in the +OTG host hardware - it unconditionally accepts any PID. + +fiq_fsm: add missing case for fiq_fsm_tt_in_use() + +Certain combinations of bitrate and endpoint activity could +result in a periodic transaction erroneously getting started +while the previous Isochronous OUT was still active. + +fiq_fsm: clear hcintmsk for aborted transactions + +Prevents the FIQ from erroneously handling interrupts +on a timed out channel. + +fiq_fsm: enable by default + +fiq_fsm: fix dequeues for non-periodic split transactions + +If a dequeue happened between the SSPLIT and CSPLIT phases of the +transaction, the HCD would never receive an interrupt. + +fiq_fsm: Disable by default + +fiq_fsm: Handle HC babble errors + +The HCTSIZ transfer size field raises a babble interrupt if +the counter wraps. Handle the resulting interrupt in this case. + +dwc_otg: fix interrupt registration for fiq_enable=0 + +Additionally make the module parameter conditional for wherever +hcd->fiq_state is touched. + +fiq_fsm: Enable by default --- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) + arch/arm/mach-bcm2708/bcm2708.c | 24 +- + drivers/usb/host/dwc_otg/Makefile | 3 +- + drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 47 +- + drivers/usb/host/dwc_otg/dwc_otg_driver.c | 51 +- + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 1290 ++++++++++++++++++++++++++ + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 353 +++++++ + drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S | 81 ++ + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 775 +++++++++++++--- + drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 11 + + drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 999 ++++++++++---------- + drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 113 ++- + drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 41 +- + drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c | 113 --- + drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h | 48 - + drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 8 +- + 15 files changed, 2992 insertions(+), 965 deletions(-) + create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c + create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h + create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S + delete mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c + delete mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 1904f6a..22300f0 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -501,6 +501,7 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - dwc_otg_transaction_type_e tr_type; - dwc_otg_qtd_t *qtd; - gintmsk_data_t intr_mask = {.d32 = 0 }; -+ hprt0_data_t hprt0 = { .d32 = 0 }; +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index 320b5d2..ef0935f 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -330,22 +330,13 @@ static struct resource bcm2708_usb_resources[] = { + .end = IRQ_HOSTPORT, + .flags = IORESOURCE_IRQ, + }, ++ [3] = { ++ .start = IRQ_USB, ++ .end = IRQ_USB, ++ .flags = IORESOURCE_IRQ, ++ }, + }; - #ifdef DEBUG /* integrity checks (Broadcom) */ - if (NULL == hcd->core_if) { -@@ -515,6 +516,16 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - return -DWC_E_NO_DEVICE; +-bool fiq_fix_enable = true; +- +-static struct resource bcm2708_usb_resources_no_fiq_fix[] = { +- [0] = { +- .start = USB_BASE, +- .end = USB_BASE + SZ_128K - 1, +- .flags = IORESOURCE_MEM, +- }, +- [1] = { +- .start = IRQ_USB, +- .end = IRQ_USB, +- .flags = IORESOURCE_IRQ, +- }, +-}; + + static u64 usb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); + +@@ -729,11 +720,6 @@ void __init bcm2708_init(void) + #endif + bcm_register_device(&bcm2708_systemtimer_device); + bcm_register_device(&bcm2708_fb_device); +- if (!fiq_fix_enable) +- { +- bcm2708_usb_device.resource = bcm2708_usb_resources_no_fiq_fix; +- bcm2708_usb_device.num_resources = ARRAY_SIZE(bcm2708_usb_resources_no_fiq_fix); +- } + bcm_register_device(&bcm2708_usb_device); + bcm_register_device(&bcm2708_uart1_device); + bcm_register_device(&bcm2708_powerman_device); +diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile +index a56f193..e7bdd12 100644 +--- a/drivers/usb/host/dwc_otg/Makefile ++++ b/drivers/usb/host/dwc_otg/Makefile +@@ -36,7 +36,8 @@ dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o + dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o + dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o + dwc_otg-objs += dwc_otg_adp.o +-dwc_otg-objs += dwc_otg_mphi_fix.o ++dwc_otg-objs += dwc_otg_fiq_fsm.o ++dwc_otg-objs += dwc_otg_fiq_stub.o + ifneq ($(CFI),) + dwc_otg-objs += dwc_otg_cfi.o + endif +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c +index 2f8b3bd..065807f 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c +@@ -45,7 +45,6 @@ + #include "dwc_otg_driver.h" + #include "dwc_otg_pcd.h" + #include "dwc_otg_hcd.h" +-#include "dwc_otg_mphi_fix.h" + + #ifdef DEBUG + inline const char *op_state_str(dwc_otg_core_if_t * core_if) +@@ -1319,7 +1318,7 @@ static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if) + /** + * This function returns the Core Interrupt register. + */ +-static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gintmsk_data_t *reenable_gintmsk) ++static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gintmsk_data_t *reenable_gintmsk, dwc_otg_hcd_t *hcd) + { + gahbcfg_data_t gahbcfg = {.d32 = 0 }; + gintsts_data_t gintsts; +@@ -1345,16 +1344,15 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gin + } + gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts); + gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk); +- { +- unsigned long flags; +- +- // Re-enable the saved interrupts +- local_irq_save(flags); ++ if(fiq_enable) { + local_fiq_disable(); +- gintmsk.d32 |= gintmsk_common.d32; +- gintsts_saved.d32 &= ~gintmsk_common.d32; +- reenable_gintmsk->d32 = gintmsk.d32; +- local_irq_restore(flags); ++ /* Pull in the interrupts that the FIQ has masked */ ++ gintmsk.d32 |= ~(hcd->fiq_state->gintmsk_saved.d32); ++ /* for the upstairs function to reenable - have to read it here in case FIQ triggers again */ ++ reenable_gintmsk->d32 |= gintmsk.d32; ++ reenable_gintmsk->d32 |= ~(hcd->fiq_state->gintmsk_saved.d32); ++ reenable_gintmsk->d32 &= gintmsk_common.d32; ++ local_fiq_enable(); } -+ /* Some core configurations cannot support LS traffic on a FS root port */ -+ if ((hcd->fops->speed(hcd, dwc_otg_urb->priv) == USB_SPEED_LOW) && -+ (hcd->core_if->hwcfg2.b.fs_phy_type == 1) && -+ (hcd->core_if->hwcfg2.b.hs_phy_type == 1)) { -+ hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0); -+ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED) { -+ return -DWC_E_NO_DEVICE; -+ } + gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg); +@@ -1366,13 +1364,15 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gin + gintsts.d32, gintmsk.d32); + } + #endif +- if (!fiq_fix_enable){ ++ if (!fiq_enable){ + if (gahbcfg.b.glblintrmsk) + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); + else + return 0; +- } +- else { ++ } else { ++ /* Our IRQ kicker is no longer the USB hardware, it's the MPHI interface. ++ * Can't trust the global interrupt mask bit in this case. ++ */ + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); + } + +@@ -1406,7 +1406,7 @@ int32_t dwc_otg_handle_common_intr(void *dev) + { + int retval = 0; + gintsts_data_t gintsts; +- gintmsk_data_t reenable_gintmsk; ++ gintmsk_data_t gintmsk_reenable = { .d32 = 0 }; + gpwrdn_data_t gpwrdn = {.d32 = 0 }; + dwc_otg_device_t *otg_dev = dev; + dwc_otg_core_if_t *core_if = otg_dev->core_if; +@@ -1428,7 +1428,10 @@ int32_t dwc_otg_handle_common_intr(void *dev) + } + + if (core_if->hibernation_suspend <= 0) { +- gintsts.d32 = dwc_otg_read_common_intr(core_if, &reenable_gintmsk); ++ /* read_common will have to poke the FIQ's saved mask. We must then clear this mask at the end ++ * of this handler - god only knows why it's done like this ++ */ ++ gintsts.d32 = dwc_otg_read_common_intr(core_if, &gintmsk_reenable, otg_dev->hcd); + + if (gintsts.b.modemismatch) { + retval |= dwc_otg_handle_mode_mismatch_intr(core_if); +@@ -1525,11 +1528,16 @@ int32_t dwc_otg_handle_common_intr(void *dev) + gintsts.b.portintr = 1; + DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32); + retval |= 1; +- reenable_gintmsk.b.portintr = 1; ++ gintmsk_reenable.b.portintr = 1; + + } +- +- DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, reenable_gintmsk.d32); ++ /* Did we actually handle anything? if so, unmask the interrupt */ ++// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "CILOUT %1d", retval); ++// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintsts.d32); ++// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintmsk_reenable.d32); ++ if (retval) { ++ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_reenable.d32); ++ } + + } else { + DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32); +@@ -1583,6 +1591,5 @@ int32_t dwc_otg_handle_common_intr(void *dev) + } + if (core_if->lock) + DWC_SPINUNLOCK(core_if->lock); +- + return retval; + } +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c +index f06c3d22..dc7cd32 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c +@@ -56,6 +56,7 @@ + #include "dwc_otg_core_if.h" + #include "dwc_otg_pcd_if.h" + #include "dwc_otg_hcd_if.h" ++#include "dwc_otg_fiq_fsm.h" + + #define DWC_DRIVER_VERSION "3.00a 10-AUG-2012" + #define DWC_DRIVER_DESC "HS OTG USB Controller driver" +@@ -64,7 +65,6 @@ bool microframe_schedule=true; + + static const char dwc_driver_name[] = "dwc_otg"; + +-extern void* dummy_send; + + extern int pcd_init( + #ifdef LM_INTERFACE +@@ -240,13 +240,14 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { + .adp_enable = -1, + }; + +-//Global variable to switch the fiq fix on or off (declared in bcm2708.c) +-extern bool fiq_fix_enable; ++//Global variable to switch the fiq fix on or off ++bool fiq_enable = 1; + // Global variable to enable the split transaction fix +-bool fiq_split_enable = true; +-//Global variable to switch the nak holdoff on or off +-bool nak_holdoff_enable = true; ++bool fiq_fsm_enable = true; ++//Bulk split-transaction NAK holdoff in microframes ++uint16_t nak_holdoff = 8; + ++unsigned short fiq_fsm_mask = 0x07; + + /** + * This function shows the Driver Version. +@@ -800,7 +801,7 @@ static int dwc_otg_driver_probe( + dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start, + _dev->resource[0].end - + _dev->resource[0].start+1); +- if (fiq_fix_enable) ++ if (fiq_enable) + { + if (!request_mem_region(_dev->resource[1].start, + _dev->resource[1].end - _dev->resource[1].start + 1, +@@ -813,7 +814,6 @@ static int dwc_otg_driver_probe( + dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start, + _dev->resource[1].end - + _dev->resource[1].start + 1); +- dummy_send = (void *) kmalloc(16, GFP_ATOMIC); + } + + #else +@@ -902,9 +902,9 @@ static int dwc_otg_driver_probe( + */ + + #if defined(PLATFORM_INTERFACE) +- devirq = platform_get_irq(_dev, 0); ++ devirq = platform_get_irq(_dev, fiq_enable ? 0 : 1); + #else +- devirq = _dev->irq; ++ devirq = _dev->irq; + #endif + DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n", + devirq); +@@ -1071,9 +1071,9 @@ static int __init dwc_otg_driver_init(void) + int error; + struct device_driver *drv; + +- if(fiq_split_enable && !fiq_fix_enable) { +- printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n"); +- fiq_fix_enable = 1; ++ if(fiq_fsm_enable && !fiq_enable) { ++ printk(KERN_WARNING "dwc_otg: fiq_fsm_enable was set without fiq_enable! Correcting.\n"); ++ fiq_enable = 1; + } + + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name, +@@ -1095,9 +1095,9 @@ static int __init dwc_otg_driver_init(void) + printk(KERN_ERR "%s retval=%d\n", __func__, retval); + return retval; + } +- printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled"); +- printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled"); +- printk(KERN_DEBUG "dwc_otg: FIQ split fix %s\n", fiq_split_enable ? "enabled":"disabled"); ++ printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_enable ? "enabled":"disabled"); ++ printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff ? "enabled":"disabled"); ++ printk(KERN_DEBUG "dwc_otg: FIQ split-transaction FSM %s\n", fiq_fsm_enable ? "enabled":"disabled"); + + error = driver_create_file(drv, &driver_attr_version); + #ifdef DEBUG +@@ -1378,12 +1378,19 @@ MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0"); + module_param(microframe_schedule, bool, 0444); + MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler"); + +-module_param(fiq_fix_enable, bool, 0444); +-MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix"); +-module_param(nak_holdoff_enable, bool, 0444); +-MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff"); +-module_param(fiq_split_enable, bool, 0444); +-MODULE_PARM_DESC(fiq_split_enable, "Enable the FIQ fix on split transactions"); ++module_param(fiq_enable, bool, 0444); ++MODULE_PARM_DESC(fiq_enable, "Enable the FIQ"); ++module_param(nak_holdoff, ushort, 0644); ++MODULE_PARM_DESC(nak_holdoff, "Throttle duration for bulk split-transaction endpoints on a NAK. Default 8"); ++module_param(fiq_fsm_enable, bool, 0444); ++MODULE_PARM_DESC(fiq_fsm_enable, "Enable the FIQ to perform split transactions as defined by fiq_fsm_mask"); ++module_param(fiq_fsm_mask, ushort, 0444); ++MODULE_PARM_DESC(fiq_fsm_mask, "Bitmask of transactions to perform in the FIQ.\n" ++ "Bit 0 : Non-periodic split transactions\n" ++ "Bit 1 : Periodic split transactions\n" ++ "Bit 2 : High-speed multi-transfer isochronous\n" ++ "All other bits should be set 0."); ++ + + /** @page "Module Parameters" + * +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c +new file mode 100644 +index 0000000..7aad7f7 +--- /dev/null ++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c +@@ -0,0 +1,1290 @@ ++/* ++ * dwc_otg_fiq_fsm.c - The finite state machine FIQ ++ * ++ * Copyright (c) 2013 Raspberry Pi Foundation ++ * ++ * Author: Jonathan Bell ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Raspberry Pi nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This FIQ implements functionality that performs split transactions on ++ * the dwc_otg hardware without any outside intervention. A split transaction ++ * is "queued" by nominating a specific host channel to perform the entirety ++ * of a split transaction. This FIQ will then perform the microframe-precise ++ * scheduling required in each phase of the transaction until completion. ++ * ++ * The FIQ functionality is glued into the Synopsys driver via the entry point ++ * in the FSM enqueue function, and at the exit point in handling a HC interrupt ++ * for a FSM-enabled channel. ++ * ++ * NB: Large parts of this implementation have architecture-specific code. ++ * For porting this functionality to other ARM machines, the minimum is required: ++ * - An interrupt controller allowing the top-level dwc USB interrupt to be routed ++ * to the FIQ ++ * - A method of forcing a software generated interrupt from FIQ mode that then ++ * triggers an IRQ entry (with the dwc USB handler called by this IRQ number) ++ * - Guaranteed interrupt routing such that both the FIQ and SGI occur on the same ++ * processor core - there is no locking between the FIQ and IRQ (aside from ++ * local_fiq_disable) ++ * ++ */ ++ ++#include "dwc_otg_fiq_fsm.h" ++ ++ ++char buffer[1000*16]; ++int wptr; ++void notrace _fiq_print(enum fiq_debug_level dbg_lvl, volatile struct fiq_state *state, char *fmt, ...) ++{ ++ enum fiq_debug_level dbg_lvl_req = FIQDBG_ERR; ++ va_list args; ++ char text[17]; ++ hfnum_data_t hfnum = { .d32 = FIQ_READ(state->dwc_regs_base + 0x408) }; ++ ++ if((dbg_lvl & dbg_lvl_req) || dbg_lvl == FIQDBG_ERR) ++ { ++ snprintf(text, 9, " %4d:%1u ", hfnum.b.frnum/8, hfnum.b.frnum & 7); ++ va_start(args, fmt); ++ vsnprintf(text+8, 9, fmt, args); ++ va_end(args); ++ ++ memcpy(buffer + wptr, text, 16); ++ wptr = (wptr + 16) % sizeof(buffer); ++ } ++} ++ ++/** ++ * fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction ++ * @channel: channel to re-enable ++ */ ++static void fiq_fsm_restart_channel(struct fiq_state *st, int n, int force) ++{ ++ hcchar_data_t hcchar = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR) }; ++ ++ hcchar.b.chen = 0; ++ if (st->channel[n].hcchar_copy.b.eptype & 0x1) { ++ hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; ++ /* Hardware bug workaround: update the ssplit index */ ++ if (st->channel[n].hcsplt_copy.b.spltena) ++ st->channel[n].expected_uframe = (hfnum.b.frnum + 1) & 0x3FFF; ++ ++ hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; ++ } ++ ++ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, hcchar.d32); ++ hcchar.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); ++ hcchar.b.chen = 1; ++ ++ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, hcchar.d32); ++ fiq_print(FIQDBG_INT, st, "HCGO %01d %01d", n, force); ++} ++ ++/** ++ * fiq_fsm_setup_csplit() - Prepare a host channel for a CSplit transaction stage ++ * @st: Pointer to the channel's state ++ * @n : channel number ++ * ++ * Change host channel registers to perform a complete-split transaction. Being mindful of the ++ * endpoint direction, set control regs up correctly. ++ */ ++static void notrace fiq_fsm_setup_csplit(struct fiq_state *st, int n) ++{ ++ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT) }; ++ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; ++ ++ hcsplt.b.compsplt = 1; ++ if (st->channel[n].hcchar_copy.b.epdir == 1) { ++ // If IN, the CSPLIT result contains the data or a hub handshake. hctsiz = maxpacket. ++ hctsiz.b.xfersize = st->channel[n].hctsiz_copy.b.xfersize; ++ } else { ++ // If OUT, the CSPLIT result contains handshake only. ++ hctsiz.b.xfersize = 0; ++ } ++ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT, hcsplt.d32); ++ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); ++ mb(); ++} ++ ++static inline int notrace fiq_get_xfer_len(struct fiq_state *st, int n) ++{ ++ /* The xfersize register is a bit wonky. For IN transfers, it decrements by the packet size. */ ++ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; ++ ++ if (st->channel[n].hcchar_copy.b.epdir == 0) { ++ return st->channel[n].hctsiz_copy.b.xfersize; ++ } else { ++ return st->channel[n].hctsiz_copy.b.xfersize - hctsiz.b.xfersize; + } + - qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc); - if (qtd == NULL) { - DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n"); ++} ++ ++ ++/** ++ * fiq_increment_dma_buf() - update DMA address for bounce buffers after a CSPLIT ++ * ++ * Of use only for IN periodic transfers. ++ */ ++static int notrace fiq_increment_dma_buf(struct fiq_state *st, int num_channels, int n) ++{ ++ hcdma_data_t hcdma; ++ int i = st->channel[n].dma_info.index; ++ int len; ++ struct fiq_dma_blob *blob = (struct fiq_dma_blob *) st->dma_base; ++ ++ len = fiq_get_xfer_len(st, n); ++ fiq_print(FIQDBG_INT, st, "LEN: %03d", len); ++ st->channel[n].dma_info.slot_len[i] = len; ++ i++; ++ if (i > 6) ++ BUG(); ++ ++ hcdma.d32 = (dma_addr_t) &blob->channel[n].index[i].buf[0]; ++ FIQ_WRITE(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); ++ st->channel[n].dma_info.index = i; ++ return 0; ++} ++ ++/** ++ * fiq_reload_hctsiz() - for IN transactions, reset HCTSIZ ++ */ ++static void notrace fiq_fsm_reload_hctsiz(struct fiq_state *st, int n) ++{ ++ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; ++ hctsiz.b.xfersize = st->channel[n].hctsiz_copy.b.xfersize; ++ hctsiz.b.pktcnt = 1; ++ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); ++} ++ ++/** ++ * fiq_iso_out_advance() - update DMA address and split position bits ++ * for isochronous OUT transactions. ++ * ++ * Returns 1 if this is the last packet queued, 0 otherwise. Split-ALL and ++ * Split-BEGIN states are not handled - this is done when the transaction was queued. ++ * ++ * This function must only be called from the FIQ_ISO_OUT_ACTIVE state. ++ */ ++static int notrace fiq_iso_out_advance(struct fiq_state *st, int num_channels, int n) ++{ ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ hcdma_data_t hcdma; ++ struct fiq_dma_blob *blob = (struct fiq_dma_blob *) st->dma_base; ++ int last = 0; ++ int i = st->channel[n].dma_info.index; ++ ++ fiq_print(FIQDBG_INT, st, "ADV %01d %01d ", n, i); ++ i++; ++ if (i == 4) ++ last = 1; ++ if (st->channel[n].dma_info.slot_len[i+1] == 255) ++ last = 1; ++ ++ /* New DMA address - address of bounce buffer referred to in index */ ++ hcdma.d32 = (uint32_t) &blob->channel[n].index[i].buf[0]; ++ //hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n)); ++ //hcdma.d32 += st->channel[n].dma_info.slot_len[i]; ++ fiq_print(FIQDBG_INT, st, "LAST: %01d ", last); ++ fiq_print(FIQDBG_INT, st, "LEN: %03d", st->channel[n].dma_info.slot_len[i]); ++ hcsplt.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT); ++ hctsiz.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ); ++ hcsplt.b.xactpos = (last) ? ISOC_XACTPOS_END : ISOC_XACTPOS_MID; ++ /* Set up new packet length */ ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.xfersize = st->channel[n].dma_info.slot_len[i]; ++ fiq_print(FIQDBG_INT, st, "%08x", hctsiz.d32); ++ ++ st->channel[n].dma_info.index++; ++ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT, hcsplt.d32); ++ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); ++ FIQ_WRITE(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); ++ return last; ++} ++ ++/** ++ * fiq_fsm_tt_next_isoc() - queue next pending isochronous out start-split on a TT ++ * ++ * Despite the limitations of the DWC core, we can force a microframe pipeline of ++ * isochronous OUT start-split transactions while waiting for a corresponding other-type ++ * of endpoint to finish its CSPLITs. TTs have big periodic buffers therefore it ++ * is very unlikely that filling the start-split FIFO will cause data loss. ++ * This allows much better interleaving of transactions in an order-independent way- ++ * there is no requirement to prioritise isochronous, just a state-space search has ++ * to be performed on each periodic start-split complete interrupt. ++ */ ++static int notrace fiq_fsm_tt_next_isoc(struct fiq_state *st, int num_channels, int n) ++{ ++ int hub_addr = st->channel[n].hub_addr; ++ int port_addr = st->channel[n].port_addr; ++ int i, poked = 0; ++ for (i = 0; i < num_channels; i++) { ++ if (i == n || st->channel[i].fsm == FIQ_PASSTHROUGH) ++ continue; ++ if (st->channel[i].hub_addr == hub_addr && ++ st->channel[i].port_addr == port_addr) { ++ switch (st->channel[i].fsm) { ++ case FIQ_PER_ISO_OUT_PENDING: ++ if (st->channel[i].nrpackets == 1) { ++ st->channel[i].fsm = FIQ_PER_ISO_OUT_LAST; ++ } else { ++ st->channel[i].fsm = FIQ_PER_ISO_OUT_ACTIVE; ++ } ++ fiq_fsm_restart_channel(st, i, 0); ++ poked = 1; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ if (poked) ++ break; ++ } ++ return poked; ++} ++ ++/** ++ * fiq_fsm_tt_in_use() - search for host channels using this TT ++ * @n: Channel to use as reference ++ * ++ */ ++int notrace noinline fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n) ++{ ++ int hub_addr = st->channel[n].hub_addr; ++ int port_addr = st->channel[n].port_addr; ++ int i, in_use = 0; ++ for (i = 0; i < num_channels; i++) { ++ if (i == n || st->channel[i].fsm == FIQ_PASSTHROUGH) ++ continue; ++ switch (st->channel[i].fsm) { ++ /* TT is reserved for channels that are in the middle of a periodic ++ * split transaction. ++ */ ++ case FIQ_PER_SSPLIT_STARTED: ++ case FIQ_PER_CSPLIT_WAIT: ++ case FIQ_PER_CSPLIT_NYET1: ++ //case FIQ_PER_CSPLIT_POLL: ++ case FIQ_PER_ISO_OUT_ACTIVE: ++ case FIQ_PER_ISO_OUT_LAST: ++ if (st->channel[i].hub_addr == hub_addr && ++ st->channel[i].port_addr == port_addr) { ++ in_use = 1; ++ } ++ break; ++ default: ++ break; ++ } ++ if (in_use) ++ break; ++ } ++ return in_use; ++} ++ ++/** ++ * fiq_fsm_more_csplits() - determine whether additional CSPLITs need ++ * to be issued for this IN transaction. ++ * ++ * We cannot tell the inbound PID of a data packet due to hardware limitations. ++ * we need to make an educated guess as to whether we need to queue another CSPLIT ++ * or not. A no-brainer is when we have received enough data to fill the endpoint ++ * size, but for endpoints that give variable-length data then we have to resort ++ * to heuristics. ++ * ++ * We also return whether this is the last CSPLIT to be queued, again based on ++ * heuristics. This is to allow a 1-uframe overlap of periodic split transactions. ++ * Note: requires at least 1 CSPLIT to have been performed prior to being called. ++ */ ++ ++/* ++ * We need some way of guaranteeing if a returned periodic packet of size X ++ * has a DATA0 PID. ++ * The heuristic value of 144 bytes assumes that the received data has maximal ++ * bit-stuffing and the clock frequency of the transmitting device is at the lowest ++ * permissible limit. If the transfer length results in a final packet size ++ * 144 < p <= 188, then an erroneous CSPLIT will be issued. ++ * Also used to ensure that an endpoint will nominally only return a single ++ * complete-split worth of data. ++ */ ++#define DATA0_PID_HEURISTIC 144 ++ ++static int notrace noinline fiq_fsm_more_csplits(struct fiq_state *state, int n, int *probably_last) ++{ ++ ++ int i; ++ int total_len = 0; ++ int more_needed = 1; ++ struct fiq_channel_state *st = &state->channel[n]; ++ ++ for (i = 0; i < st->dma_info.index; i++) { ++ total_len += st->dma_info.slot_len[i]; ++ } ++ ++ *probably_last = 0; ++ ++ if (st->hcchar_copy.b.eptype == 0x3) { ++ /* ++ * An interrupt endpoint will take max 2 CSPLITs. if we are receiving data ++ * then this is definitely the last CSPLIT. ++ */ ++ *probably_last = 1; ++ } else { ++ /* Isoc IN. This is a bit risky if we are the first transaction: ++ * we may have been held off slightly. */ ++ if (i > 1 && st->dma_info.slot_len[st->dma_info.index-1] <= DATA0_PID_HEURISTIC) { ++ more_needed = 0; ++ } ++ /* If in the next uframe we will receive enough data to fill the endpoint, ++ * then only issue 1 more csplit. ++ */ ++ if (st->hctsiz_copy.b.xfersize - total_len <= DATA0_PID_HEURISTIC) ++ *probably_last = 1; ++ } ++ ++ if (total_len >= st->hctsiz_copy.b.xfersize || ++ i == 6 || total_len == 0) ++ /* Note: due to bit stuffing it is possible to have > 6 CSPLITs for ++ * a single endpoint. Accepting more would completely break our scheduling mechanism though ++ * - in these extreme cases we will pass through a truncated packet. ++ */ ++ more_needed = 0; ++ ++ return more_needed; ++} ++ ++/** ++ * fiq_fsm_too_late() - Test transaction for lateness ++ * ++ * If a SSPLIT for a large IN transaction is issued too late in a frame, ++ * the hub will disable the port to the device and respond with ERR handshakes. ++ * The hub status endpoint will not reflect this change. ++ * Returns 1 if we will issue a SSPLIT that will result in a device babble. ++ */ ++int notrace fiq_fsm_too_late(struct fiq_state *st, int n) ++{ ++ int uframe; ++ hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; ++ uframe = hfnum.b.frnum & 0x7; ++ if ((uframe < 6) && (st->channel[n].nrpackets + 1 + uframe > 7)) { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++ ++/** ++ * fiq_fsm_start_next_periodic() - A half-arsed attempt at a microframe pipeline ++ * ++ * Search pending transactions in the start-split pending state and queue them. ++ * Don't queue packets in uframe .5 (comes out in .6) (USB2.0 11.18.4). ++ * Note: we specifically don't do isochronous OUT transactions first because better ++ * use of the TT's start-split fifo can be achieved by pipelining an IN before an OUT. ++ */ ++static void notrace noinline fiq_fsm_start_next_periodic(struct fiq_state *st, int num_channels) ++{ ++ int n; ++ hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; ++ if ((hfnum.b.frnum & 0x7) == 5) ++ return; ++ for (n = 0; n < num_channels; n++) { ++ if (st->channel[n].fsm == FIQ_PER_SSPLIT_QUEUED) { ++ /* Check to see if any other transactions are using this TT */ ++ if(!fiq_fsm_tt_in_use(st, num_channels, n)) { ++ if (!fiq_fsm_too_late(st, n)) { ++ st->channel[n].fsm = FIQ_PER_SSPLIT_STARTED; ++ fiq_print(FIQDBG_INT, st, "NEXTPER "); ++ fiq_fsm_restart_channel(st, n, 0); ++ } else { ++ st->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; ++ } ++ break; ++ } ++ } ++ } ++ for (n = 0; n < num_channels; n++) { ++ if (st->channel[n].fsm == FIQ_PER_ISO_OUT_PENDING) { ++ if (!fiq_fsm_tt_in_use(st, num_channels, n)) { ++ fiq_print(FIQDBG_INT, st, "NEXTISO "); ++ st->channel[n].fsm = FIQ_PER_ISO_OUT_ACTIVE; ++ fiq_fsm_restart_channel(st, n, 0); ++ break; ++ } ++ } ++ } ++} ++ ++/** ++ * fiq_fsm_update_hs_isoc() - update isochronous frame and transfer data ++ * @state: Pointer to fiq_state ++ * @n: Channel transaction is active on ++ * @hcint: Copy of host channel interrupt register ++ * ++ * Returns 0 if there are no more transactions for this HC to do, 1 ++ * otherwise. ++ */ ++static int notrace noinline fiq_fsm_update_hs_isoc(struct fiq_state *state, int n, hcint_data_t hcint) ++{ ++ struct fiq_channel_state *st = &state->channel[n]; ++ int xfer_len = 0, nrpackets = 0; ++ hcdma_data_t hcdma; ++ fiq_print(FIQDBG_INT, state, "HSISO %02d", n); ++ ++ xfer_len = fiq_get_xfer_len(state, n); ++ st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].actual_length = xfer_len; ++ ++ st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].status = hcint.d32; ++ ++ st->hs_isoc_info.index++; ++ if (st->hs_isoc_info.index == st->hs_isoc_info.nrframes) { ++ return 0; ++ } ++ ++ /* grab the next DMA address offset from the array */ ++ hcdma.d32 = st->hcdma_copy.d32 + st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].offset; ++ FIQ_WRITE(state->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); ++ ++ /* We need to set multi_count. This is a bit tricky - has to be set per-transaction as ++ * the core needs to be told to send the correct number. Caution: for IN transfers, ++ * this is always set to the maximum size of the endpoint. */ ++ xfer_len = st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].length; ++ /* Integer divide in a FIQ: fun. FIXME: make this not suck */ ++ nrpackets = (xfer_len + st->hcchar_copy.b.mps - 1) / st->hcchar_copy.b.mps; ++ if (nrpackets == 0) ++ nrpackets = 1; ++ st->hcchar_copy.b.multicnt = nrpackets; ++ st->hctsiz_copy.b.pktcnt = nrpackets; ++ ++ /* Initial PID also needs to be set */ ++ if (st->hcchar_copy.b.epdir == 0) { ++ st->hctsiz_copy.b.xfersize = xfer_len; ++ switch (st->hcchar_copy.b.multicnt) { ++ case 1: ++ st->hctsiz_copy.b.pid = DWC_PID_DATA0; ++ break; ++ case 2: ++ case 3: ++ st->hctsiz_copy.b.pid = DWC_PID_MDATA; ++ break; ++ } ++ ++ } else { ++ switch (st->hcchar_copy.b.multicnt) { ++ st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps; ++ case 1: ++ st->hctsiz_copy.b.pid = DWC_PID_DATA0; ++ break; ++ case 2: ++ st->hctsiz_copy.b.pid = DWC_PID_DATA1; ++ break; ++ case 3: ++ st->hctsiz_copy.b.pid = DWC_PID_DATA2; ++ break; ++ } ++ } ++ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, st->hctsiz_copy.d32); ++ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, st->hcchar_copy.d32); ++ /* Channel is enabled on hcint handler exit */ ++ fiq_print(FIQDBG_INT, state, "HSISOOUT"); ++ return 1; ++} ++ ++ ++/** ++ * fiq_fsm_do_sof() - FSM start-of-frame interrupt handler ++ * @state: Pointer to the state struct passed from banked FIQ mode registers. ++ * @num_channels: set according to the DWC hardware configuration ++ * ++ * The SOF handler in FSM mode has two functions ++ * 1. Hold off SOF from causing schedule advancement in IRQ context if there's ++ * nothing to do ++ * 2. Advance certain FSM states that require either a microframe delay, or a microframe ++ * of holdoff. ++ * ++ * The second part is architecture-specific to mach-bcm2835 - ++ * a sane interrupt controller would have a mask register for ARM interrupt sources ++ * to be promoted to the nFIQ line, but it doesn't. Instead a single interrupt ++ * number (USB) can be enabled. This means that certain parts of the USB specification ++ * that require "wait a little while, then issue another packet" cannot be fulfilled with ++ * the timing granularity required to achieve optimal throughout. The workaround is to use ++ * the SOF "timer" (125uS) to perform this task. ++ */ ++static int notrace noinline fiq_fsm_do_sof(struct fiq_state *state, int num_channels) ++{ ++ hfnum_data_t hfnum = { .d32 = FIQ_READ(state->dwc_regs_base + HFNUM) }; ++ int n; ++ int kick_irq = 0; ++ ++ if ((hfnum.b.frnum & 0x7) == 1) { ++ /* We cannot issue csplits for transactions in the last frame past (n+1).1 ++ * Check to see if there are any transactions that are stale. ++ * Boot them out. ++ */ ++ for (n = 0; n < num_channels; n++) { ++ switch (state->channel[n].fsm) { ++ case FIQ_PER_CSPLIT_WAIT: ++ case FIQ_PER_CSPLIT_NYET1: ++ case FIQ_PER_CSPLIT_POLL: ++ case FIQ_PER_CSPLIT_LAST: ++ /* Check if we are no longer in the same full-speed frame. */ ++ if (((state->channel[n].expected_uframe & 0x3FFF) & ~0x7) < ++ (hfnum.b.frnum & ~0x7)) ++ state->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ ++ for (n = 0; n < num_channels; n++) { ++ switch (state->channel[n].fsm) { ++ ++ case FIQ_NP_SSPLIT_RETRY: ++ case FIQ_NP_IN_CSPLIT_RETRY: ++ case FIQ_NP_OUT_CSPLIT_RETRY: ++ fiq_fsm_restart_channel(state, n, 0); ++ break; ++ ++ case FIQ_HS_ISOC_SLEEPING: ++ state->channel[n].fsm = FIQ_HS_ISOC_TURBO; ++ fiq_fsm_restart_channel(state, n, 0); ++ break; ++ ++ case FIQ_PER_SSPLIT_QUEUED: ++ if ((hfnum.b.frnum & 0x7) == 5) ++ break; ++ if(!fiq_fsm_tt_in_use(state, num_channels, n)) { ++ if (!fiq_fsm_too_late(state, n)) { ++ fiq_print(FIQDBG_INT, st, "SOF GO %01d", n); ++ fiq_fsm_restart_channel(state, n, 0); ++ state->channel[n].fsm = FIQ_PER_SSPLIT_STARTED; ++ } else { ++ /* Transaction cannot be started without risking a device babble error */ ++ state->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; ++ state->haintmsk_saved.b2.chint &= ~(1 << n); ++ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, 0); ++ kick_irq |= 1; ++ } ++ } ++ break; ++ ++ case FIQ_PER_ISO_OUT_PENDING: ++ /* Ordinarily, this should be poked after the SSPLIT ++ * complete interrupt for a competing transfer on the same ++ * TT. Doesn't happen for aborted transactions though. ++ */ ++ if ((hfnum.b.frnum & 0x7) >= 5) ++ break; ++ if (!fiq_fsm_tt_in_use(state, num_channels, n)) { ++ /* Hardware bug. SOF can sometimes occur after the channel halt interrupt ++ * that caused this. ++ */ ++ fiq_fsm_restart_channel(state, n, 0); ++ fiq_print(FIQDBG_INT, state, "SOF ISOC"); ++ if (state->channel[n].nrpackets == 1) { ++ state->channel[n].fsm = FIQ_PER_ISO_OUT_LAST; ++ } else { ++ state->channel[n].fsm = FIQ_PER_ISO_OUT_ACTIVE; ++ } ++ } ++ break; ++ ++ case FIQ_PER_CSPLIT_WAIT: ++ /* we are guaranteed to be in this state if and only if the SSPLIT interrupt ++ * occurred when the bus transaction occurred. The SOF interrupt reversal bug ++ * will utterly bugger this up though. ++ */ ++ if (hfnum.b.frnum != state->channel[n].expected_uframe) { ++ fiq_print(FIQDBG_INT, state, "SOFCS %d ", n); ++ state->channel[n].fsm = FIQ_PER_CSPLIT_POLL; ++ fiq_fsm_restart_channel(state, n, 0); ++ fiq_fsm_start_next_periodic(state, num_channels); ++ ++ } ++ break; ++ ++ case FIQ_PER_SPLIT_TIMEOUT: ++ case FIQ_DEQUEUE_ISSUED: ++ /* Ugly: we have to force a HCD interrupt. ++ * Poke the mask for the channel in question. ++ * We will take a fake SOF because of this, but ++ * that's OK. ++ */ ++ state->haintmsk_saved.b2.chint &= ~(1 << n); ++ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, 0); ++ kick_irq |= 1; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ if (state->kick_np_queues || ++ dwc_frame_num_le(state->next_sched_frame, hfnum.b.frnum)) ++ kick_irq |= 1; ++ ++ return !kick_irq; ++} ++ ++ ++/** ++ * fiq_fsm_do_hcintr() - FSM host channel interrupt handler ++ * @state: Pointer to the FIQ state struct ++ * @num_channels: Number of channels as per hardware config ++ * @n: channel for which HAINT(i) was raised ++ * ++ * An important property is that only the CHHLT interrupt is unmasked. Unfortunately, AHBerr is as well. ++ */ ++static int notrace noinline fiq_fsm_do_hcintr(struct fiq_state *state, int num_channels, int n) ++{ ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ hcint_data_t hcint_probe; ++ hcchar_data_t hcchar; ++ int handled = 0; ++ int restart = 0; ++ int last_csplit = 0; ++ int start_next_periodic = 0; ++ struct fiq_channel_state *st = &state->channel[n]; ++ hfnum_data_t hfnum; ++ ++ hcint.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINT); ++ hcintmsk.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK); ++ hcint_probe.d32 = hcint.d32 & hcintmsk.d32; ++ ++ if (st->fsm != FIQ_PASSTHROUGH) { ++ fiq_print(FIQDBG_INT, state, "HC%01d ST%02d", n, st->fsm); ++ fiq_print(FIQDBG_INT, state, "%08x", hcint.d32); ++ } ++ ++ switch (st->fsm) { ++ ++ case FIQ_PASSTHROUGH: ++ case FIQ_DEQUEUE_ISSUED: ++ /* doesn't belong to us, kick it upstairs */ ++ break; ++ ++ case FIQ_PASSTHROUGH_ERRORSTATE: ++ /* We are here to emulate the error recovery mechanism of the dwc HCD. ++ * Several interrupts are unmasked if a previous transaction failed - it's ++ * death for the FIQ to attempt to handle them as the channel isn't halted. ++ * Emulate what the HCD does in this situation: mask and continue. ++ * The FSM has no other state setup so this has to be handled out-of-band. ++ */ ++ fiq_print(FIQDBG_ERR, state, "ERRST %02d", n); ++ if (hcint_probe.b.nak || hcint_probe.b.ack || hcint_probe.b.datatglerr) { ++ fiq_print(FIQDBG_ERR, state, "RESET %02d", n); ++ st->nr_errors = 0; ++ hcintmsk.b.nak = 0; ++ hcintmsk.b.ack = 0; ++ hcintmsk.b.datatglerr = 0; ++ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, hcintmsk.d32); ++ return 1; ++ } ++ if (hcint_probe.b.chhltd) { ++ fiq_print(FIQDBG_ERR, state, "CHHLT %02d", n); ++ fiq_print(FIQDBG_ERR, state, "%08x", hcint.d32); ++ return 0; ++ } ++ break; ++ ++ /* Non-periodic state groups */ ++ case FIQ_NP_SSPLIT_STARTED: ++ case FIQ_NP_SSPLIT_RETRY: ++ /* Got a HCINT for a NP SSPLIT. Expected ACK / NAK / fail */ ++ if (hcint.b.ack) { ++ /* SSPLIT complete. For OUT, the data has been sent. For IN, the LS transaction ++ * will start shortly. SOF needs to kick the transaction to prevent a NYET flood. ++ */ ++ if(st->hcchar_copy.b.epdir == 1) ++ st->fsm = FIQ_NP_IN_CSPLIT_RETRY; ++ else ++ st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; ++ st->nr_errors = 0; ++ handled = 1; ++ fiq_fsm_setup_csplit(state, n); ++ } else if (hcint.b.nak) { ++ // No buffer space in TT. Retry on a uframe boundary. ++ st->fsm = FIQ_NP_SSPLIT_RETRY; ++ handled = 1; ++ } else if (hcint.b.xacterr) { ++ // The only other one we care about is xacterr. This implies HS bus error - retry. ++ st->nr_errors++; ++ st->fsm = FIQ_NP_SSPLIT_RETRY; ++ if (st->nr_errors >= 3) { ++ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; ++ } else { ++ handled = 1; ++ restart = 1; ++ } ++ } else { ++ st->fsm = FIQ_NP_SPLIT_LS_ABORTED; ++ handled = 0; ++ restart = 0; ++ } ++ break; ++ ++ case FIQ_NP_IN_CSPLIT_RETRY: ++ /* Received a CSPLIT done interrupt. ++ * Expected Data/NAK/STALL/NYET for IN. ++ */ ++ if (hcint.b.xfercomp) { ++ /* For IN, data is present. */ ++ st->fsm = FIQ_NP_SPLIT_DONE; ++ } else if (hcint.b.nak) { ++ /* no endpoint data. Punt it upstairs */ ++ st->fsm = FIQ_NP_SPLIT_DONE; ++ } else if (hcint.b.nyet) { ++ /* CSPLIT NYET - retry on a uframe boundary. */ ++ handled = 1; ++ st->nr_errors = 0; ++ } else if (hcint.b.datatglerr) { ++ /* data toggle errors do not set the xfercomp bit. */ ++ st->fsm = FIQ_NP_SPLIT_LS_ABORTED; ++ } else if (hcint.b.xacterr) { ++ /* HS error. Retry immediate */ ++ st->fsm = FIQ_NP_IN_CSPLIT_RETRY; ++ st->nr_errors++; ++ if (st->nr_errors >= 3) { ++ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; ++ } else { ++ handled = 1; ++ restart = 1; ++ } ++ } else if (hcint.b.stall || hcint.b.bblerr) { ++ /* A STALL implies either a LS bus error or a genuine STALL. */ ++ st->fsm = FIQ_NP_SPLIT_LS_ABORTED; ++ } else { ++ /* Hardware bug. It's possible in some cases to ++ * get a channel halt with nothing else set when ++ * the response was a NYET. Treat as local 3-strikes retry. ++ */ ++ hcint_data_t hcint_test = hcint; ++ hcint_test.b.chhltd = 0; ++ if (!hcint_test.d32) { ++ st->nr_errors++; ++ if (st->nr_errors >= 3) { ++ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; ++ } else { ++ handled = 1; ++ } ++ } else { ++ /* Bail out if something unexpected happened */ ++ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; ++ } ++ } ++ break; ++ ++ case FIQ_NP_OUT_CSPLIT_RETRY: ++ /* Received a CSPLIT done interrupt. ++ * Expected ACK/NAK/STALL/NYET/XFERCOMP for OUT.*/ ++ if (hcint.b.xfercomp) { ++ st->fsm = FIQ_NP_SPLIT_DONE; ++ } else if (hcint.b.nak) { ++ // The HCD will implement the holdoff on frame boundaries. ++ st->fsm = FIQ_NP_SPLIT_DONE; ++ } else if (hcint.b.nyet) { ++ // Hub still processing. ++ st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; ++ handled = 1; ++ st->nr_errors = 0; ++ //restart = 1; ++ } else if (hcint.b.xacterr) { ++ /* HS error. retry immediate */ ++ st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; ++ st->nr_errors++; ++ if (st->nr_errors >= 3) { ++ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; ++ } else { ++ handled = 1; ++ restart = 1; ++ } ++ } else if (hcint.b.stall) { ++ /* LS bus error or genuine stall */ ++ st->fsm = FIQ_NP_SPLIT_LS_ABORTED; ++ } else { ++ /* ++ * Hardware bug. It's possible in some cases to get a ++ * channel halt with nothing else set when the response was a NYET. ++ * Treat as local 3-strikes retry. ++ */ ++ hcint_data_t hcint_test = hcint; ++ hcint_test.b.chhltd = 0; ++ if (!hcint_test.d32) { ++ st->nr_errors++; ++ if (st->nr_errors >= 3) { ++ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; ++ } else { ++ handled = 1; ++ } ++ } else { ++ // Something unexpected happened. AHBerror or babble perhaps. Let the IRQ deal with it. ++ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; ++ } ++ } ++ break; ++ ++ /* Periodic split states (except isoc out) */ ++ case FIQ_PER_SSPLIT_STARTED: ++ /* Expect an ACK or failure for SSPLIT */ ++ if (hcint.b.ack) { ++ /* ++ * SSPLIT transfer complete interrupt - the generation of this interrupt is fraught with bugs. ++ * For a packet queued in microframe n-3 to appear in n-2, if the channel is enabled near the EOF1 ++ * point for microframe n-3, the packet will not appear on the bus until microframe n. ++ * Additionally, the generation of the actual interrupt is dodgy. For a packet appearing on the bus ++ * in microframe n, sometimes the interrupt is generated immediately. Sometimes, it appears in n+1 ++ * coincident with SOF for n+1. ++ * SOF is also buggy. It can sometimes be raised AFTER the first bus transaction has taken place. ++ * These appear to be caused by timing/clock crossing bugs within the core itself. ++ * State machine workaround. ++ */ ++ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); ++ hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); ++ fiq_fsm_setup_csplit(state, n); ++ /* Poke the oddfrm bit. If we are equivalent, we received the interrupt at the correct ++ * time. If not, then we're in the next SOF. ++ */ ++ if ((hfnum.b.frnum & 0x1) == hcchar.b.oddfrm) { ++ fiq_print(FIQDBG_INT, state, "CSWAIT %01d", n); ++ st->expected_uframe = hfnum.b.frnum; ++ st->fsm = FIQ_PER_CSPLIT_WAIT; ++ } else { ++ fiq_print(FIQDBG_INT, state, "CSPOL %01d", n); ++ /* For isochronous IN endpoints, ++ * we need to hold off if we are expecting a lot of data */ ++ if (st->hcchar_copy.b.mps < DATA0_PID_HEURISTIC) { ++ start_next_periodic = 1; ++ } ++ /* Danger will robinson: we are in a broken state. If our first interrupt after ++ * this is a NYET, it will be delayed by 1 uframe and result in an unrecoverable ++ * lag. Unmask the NYET interrupt. ++ */ ++ st->expected_uframe = (hfnum.b.frnum + 1) & 0x3FFF; ++ st->fsm = FIQ_PER_CSPLIT_BROKEN_NYET1; ++ restart = 1; ++ } ++ handled = 1; ++ } else if (hcint.b.xacterr) { ++ /* 3-strikes retry is enabled, we have hit our max nr_errors */ ++ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; ++ start_next_periodic = 1; ++ } else { ++ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; ++ start_next_periodic = 1; ++ } ++ /* We can now queue the next isochronous OUT transaction, if one is pending. */ ++ if(fiq_fsm_tt_next_isoc(state, num_channels, n)) { ++ fiq_print(FIQDBG_INT, state, "NEXTISO "); ++ } ++ break; ++ ++ case FIQ_PER_CSPLIT_NYET1: ++ /* First CSPLIT attempt was a NYET. If we get a subsequent NYET, ++ * we are too late and the TT has dropped its CSPLIT fifo. ++ */ ++ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); ++ hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); ++ start_next_periodic = 1; ++ if (hcint.b.nak) { ++ st->fsm = FIQ_PER_SPLIT_DONE; ++ } else if (hcint.b.xfercomp) { ++ fiq_increment_dma_buf(state, num_channels, n); ++ st->fsm = FIQ_PER_CSPLIT_POLL; ++ st->nr_errors = 0; ++ if (fiq_fsm_more_csplits(state, n, &last_csplit)) { ++ handled = 1; ++ restart = 1; ++ if (!last_csplit) ++ start_next_periodic = 0; ++ } else { ++ st->fsm = FIQ_PER_SPLIT_DONE; ++ } ++ } else if (hcint.b.nyet) { ++ /* Doh. Data lost. */ ++ st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; ++ } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { ++ st->fsm = FIQ_PER_SPLIT_LS_ABORTED; ++ } else { ++ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; ++ } ++ break; ++ ++ case FIQ_PER_CSPLIT_BROKEN_NYET1: ++ /* ++ * we got here because our host channel is in the delayed-interrupt ++ * state and we cannot take a NYET interrupt any later than when it ++ * occurred. Disable then re-enable the channel if this happens to force ++ * CSPLITs to occur at the right time. ++ */ ++ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); ++ hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); ++ fiq_print(FIQDBG_INT, state, "BROK: %01d ", n); ++ if (hcint.b.nak) { ++ st->fsm = FIQ_PER_SPLIT_DONE; ++ start_next_periodic = 1; ++ } else if (hcint.b.xfercomp) { ++ fiq_increment_dma_buf(state, num_channels, n); ++ if (fiq_fsm_more_csplits(state, n, &last_csplit)) { ++ st->fsm = FIQ_PER_CSPLIT_POLL; ++ handled = 1; ++ restart = 1; ++ start_next_periodic = 1; ++ /* Reload HCTSIZ for the next transfer */ ++ fiq_fsm_reload_hctsiz(state, n); ++ if (!last_csplit) ++ start_next_periodic = 0; ++ } else { ++ st->fsm = FIQ_PER_SPLIT_DONE; ++ } ++ } else if (hcint.b.nyet) { ++ st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; ++ start_next_periodic = 1; ++ } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { ++ /* Local 3-strikes retry is handled by the core. This is a ERR response.*/ ++ st->fsm = FIQ_PER_SPLIT_LS_ABORTED; ++ } else { ++ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; ++ } ++ break; ++ ++ case FIQ_PER_CSPLIT_POLL: ++ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); ++ hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); ++ start_next_periodic = 1; ++ if (hcint.b.nak) { ++ st->fsm = FIQ_PER_SPLIT_DONE; ++ } else if (hcint.b.xfercomp) { ++ fiq_increment_dma_buf(state, num_channels, n); ++ if (fiq_fsm_more_csplits(state, n, &last_csplit)) { ++ handled = 1; ++ restart = 1; ++ /* Reload HCTSIZ for the next transfer */ ++ fiq_fsm_reload_hctsiz(state, n); ++ if (!last_csplit) ++ start_next_periodic = 0; ++ } else { ++ st->fsm = FIQ_PER_SPLIT_DONE; ++ } ++ } else if (hcint.b.nyet) { ++ /* Are we a NYET after the first data packet? */ ++ if (st->nrpackets == 0) { ++ st->fsm = FIQ_PER_CSPLIT_NYET1; ++ handled = 1; ++ restart = 1; ++ } else { ++ /* We got a NYET when polling CSPLITs. Can happen ++ * if our heuristic fails, or if someone disables us ++ * for any significant length of time. ++ */ ++ if (st->nr_errors >= 3) { ++ st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; ++ } else { ++ st->fsm = FIQ_PER_SPLIT_DONE; ++ } ++ } ++ } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { ++ /* For xacterr, Local 3-strikes retry is handled by the core. This is a ERR response.*/ ++ st->fsm = FIQ_PER_SPLIT_LS_ABORTED; ++ } else { ++ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; ++ } ++ break; ++ ++ case FIQ_HS_ISOC_TURBO: ++ if (fiq_fsm_update_hs_isoc(state, n, hcint)) { ++ /* more transactions to come */ ++ handled = 1; ++ restart = 1; ++ fiq_print(FIQDBG_INT, state, "HSISO M "); ++ } else { ++ st->fsm = FIQ_HS_ISOC_DONE; ++ fiq_print(FIQDBG_INT, state, "HSISO F "); ++ } ++ break; ++ ++ case FIQ_HS_ISOC_ABORTED: ++ /* This abort is called by the driver rewriting the state mid-transaction ++ * which allows the dequeue mechanism to work more effectively. ++ */ ++ break; ++ ++ case FIQ_PER_ISO_OUT_ACTIVE: ++ if (hcint.b.ack) { ++ if(fiq_iso_out_advance(state, num_channels, n)) { ++ /* last OUT transfer */ ++ st->fsm = FIQ_PER_ISO_OUT_LAST; ++ /* ++ * Assuming the periodic FIFO in the dwc core ++ * actually does its job properly, we can queue ++ * the next ssplit now and in theory, the wire ++ * transactions will be in-order. ++ */ ++ // No it doesn't. It appears to process requests in host channel order. ++ //start_next_periodic = 1; ++ } ++ handled = 1; ++ restart = 1; ++ } else { ++ /* ++ * Isochronous transactions carry on regardless. Log the error ++ * and continue. ++ */ ++ //explode += 1; ++ st->nr_errors++; ++ if(fiq_iso_out_advance(state, num_channels, n)) { ++ st->fsm = FIQ_PER_ISO_OUT_LAST; ++ //start_next_periodic = 1; ++ } ++ handled = 1; ++ restart = 1; ++ } ++ break; ++ ++ case FIQ_PER_ISO_OUT_LAST: ++ if (hcint.b.ack) { ++ /* All done here */ ++ st->fsm = FIQ_PER_ISO_OUT_DONE; ++ } else { ++ st->fsm = FIQ_PER_ISO_OUT_DONE; ++ st->nr_errors++; ++ } ++ start_next_periodic = 1; ++ break; ++ ++ case FIQ_PER_SPLIT_TIMEOUT: ++ /* SOF kicked us because we overran. */ ++ start_next_periodic = 1; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (handled) { ++ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINT, hcint.d32); ++ } else { ++ /* Copy the regs into the state so the IRQ knows what to do */ ++ st->hcint_copy.d32 = hcint.d32; ++ } ++ ++ if (restart) { ++ /* Restart always implies handled. */ ++ if (restart == 2) { ++ /* For complete-split INs, the show must go on. ++ * Force a channel restart */ ++ fiq_fsm_restart_channel(state, n, 1); ++ } else { ++ fiq_fsm_restart_channel(state, n, 0); ++ } ++ } ++ if (start_next_periodic) { ++ fiq_fsm_start_next_periodic(state, num_channels); ++ } ++ if (st->fsm != FIQ_PASSTHROUGH) ++ fiq_print(FIQDBG_INT, state, "FSMOUT%02d", st->fsm); ++ ++ return handled; ++} ++ ++ ++/** ++ * dwc_otg_fiq_fsm() - Flying State Machine (monster) FIQ ++ * @state: pointer to state struct passed from the banked FIQ mode registers. ++ * @num_channels: set according to the DWC hardware configuration ++ * @dma: pointer to DMA bounce buffers for split transaction slots ++ * ++ * The FSM FIQ performs the low-level tasks that normally would be performed by the microcode ++ * inside an EHCI or similar host controller regarding split transactions. The DWC core ++ * interrupts each and every time a split transaction packet is received or sent successfully. ++ * This results in either an interrupt storm when everything is working "properly", or ++ * the interrupt latency of the system in general breaks time-sensitive periodic split ++ * transactions. Pushing the low-level, but relatively easy state machine work into the FIQ ++ * solves these problems. ++ * ++ * Return: void ++ */ ++void notrace dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels) ++{ ++ gintsts_data_t gintsts, gintsts_handled; ++ gintmsk_data_t gintmsk; ++ //hfnum_data_t hfnum; ++ haint_data_t haint, haint_handled; ++ haintmsk_data_t haintmsk; ++ int kick_irq = 0; ++ ++ gintsts_handled.d32 = 0; ++ haint_handled.d32 = 0; ++ ++ gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS); ++ gintmsk.d32 = FIQ_READ(state->dwc_regs_base + GINTMSK); ++ gintsts.d32 &= gintmsk.d32; ++ ++ if (gintsts.b.sofintr) { ++ /* For FSM mode, SOF is required to keep the state machine advance for ++ * certain stages of the periodic pipeline. It's death to mask this ++ * interrupt in that case. ++ */ ++ ++ if (!fiq_fsm_do_sof(state, num_channels)) { ++ /* Kick IRQ once. Queue advancement means that all pending transactions ++ * will get serviced when the IRQ finally executes. ++ */ ++ if (state->gintmsk_saved.b.sofintr == 1) ++ kick_irq |= 1; ++ state->gintmsk_saved.b.sofintr = 0; ++ } ++ gintsts_handled.b.sofintr = 1; ++ } ++ ++ if (gintsts.b.hcintr) { ++ int i; ++ haint.d32 = FIQ_READ(state->dwc_regs_base + HAINT); ++ haintmsk.d32 = FIQ_READ(state->dwc_regs_base + HAINTMSK); ++ haint.d32 &= haintmsk.d32; ++ haint_handled.d32 = 0; ++ for (i=0; ihaintmsk_saved.b2.chint &= ~(1 << i); ++ } else { ++ /* do_hcintr cleaned up after itself, but clear haint */ ++ haint_handled.b2.chint |= (1 << i); ++ } ++ } ++ } ++ ++ if (haint_handled.b2.chint) { ++ FIQ_WRITE(state->dwc_regs_base + HAINT, haint_handled.d32); ++ } ++ ++ if (haintmsk.d32 != (haintmsk.d32 & state->haintmsk_saved.d32)) { ++ /* ++ * This is necessary to avoid multiple retriggers of the MPHI in the case ++ * where interrupts are held off and HCINTs start to pile up. ++ * Only wake up the IRQ if a new interrupt came in, was not handled and was ++ * masked. ++ */ ++ haintmsk.d32 &= state->haintmsk_saved.d32; ++ FIQ_WRITE(state->dwc_regs_base + HAINTMSK, haintmsk.d32); ++ kick_irq |= 1; ++ } ++ /* Top-Level interrupt - always handled because it's level-sensitive */ ++ gintsts_handled.b.hcintr = 1; ++ } ++ ++ ++ /* Clear the bits in the saved register that were not handled but were triggered. */ ++ state->gintmsk_saved.d32 &= ~(gintsts.d32 & ~gintsts_handled.d32); ++ ++ /* FIQ didn't handle something - mask has changed - write new mask */ ++ if (gintmsk.d32 != (gintmsk.d32 & state->gintmsk_saved.d32)) { ++ gintmsk.d32 &= state->gintmsk_saved.d32; ++ gintmsk.b.sofintr = 1; ++ FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32); ++// fiq_print(FIQDBG_INT, state, "KICKGINT"); ++// fiq_print(FIQDBG_INT, state, "%08x", gintmsk.d32); ++// fiq_print(FIQDBG_INT, state, "%08x", state->gintmsk_saved.d32); ++ kick_irq |= 1; ++ } ++ ++ if (gintsts_handled.d32) { ++ /* Only applies to edge-sensitive bits in GINTSTS */ ++ FIQ_WRITE(state->dwc_regs_base + GINTSTS, gintsts_handled.d32); ++ } ++ ++ /* We got an interrupt, didn't handle it. */ ++ if (kick_irq) { ++ state->mphi_int_count++; ++ FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send); ++ FIQ_WRITE(state->mphi_regs.outddb, (1<<29)); ++ ++ } ++ state->fiq_done++; ++ mb(); ++} ++ ++ ++/** ++ * dwc_otg_fiq_nop() - FIQ "lite" ++ * @state: pointer to state struct passed from the banked FIQ mode registers. ++ * ++ * The "nop" handler does not intervene on any interrupts other than SOF. ++ * It is limited in scope to deciding at each SOF if the IRQ SOF handler (which deals ++ * with non-periodic/periodic queues) needs to be kicked. ++ * ++ * This is done to hold off the SOF interrupt, which occurs at a rate of 8000 per second. ++ * ++ * Return: void ++ */ ++void notrace dwc_otg_fiq_nop(struct fiq_state *state) ++{ ++ gintsts_data_t gintsts, gintsts_handled; ++ gintmsk_data_t gintmsk; ++ hfnum_data_t hfnum; ++ ++ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); ++ gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS); ++ gintmsk.d32 = FIQ_READ(state->dwc_regs_base + GINTMSK); ++ gintsts.d32 &= gintmsk.d32; ++ gintsts_handled.d32 = 0; ++ ++ if (gintsts.b.sofintr) { ++ if (!state->kick_np_queues && ++ dwc_frame_num_gt(state->next_sched_frame, hfnum.b.frnum)) { ++ /* SOF handled, no work to do, just ACK interrupt */ ++ gintsts_handled.b.sofintr = 1; ++ } else { ++ /* Kick IRQ */ ++ state->gintmsk_saved.b.sofintr = 0; ++ } ++ } ++ ++ /* Reset handled interrupts */ ++ if(gintsts_handled.d32) { ++ FIQ_WRITE(state->dwc_regs_base + GINTSTS, gintsts_handled.d32); ++ } ++ ++ /* Clear the bits in the saved register that were not handled but were triggered. */ ++ state->gintmsk_saved.d32 &= ~(gintsts.d32 & ~gintsts_handled.d32); ++ ++ /* We got an interrupt, didn't handle it and want to mask it */ ++ if (~(state->gintmsk_saved.d32)) { ++ state->mphi_int_count++; ++ gintmsk.d32 &= state->gintmsk_saved.d32; ++ FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32); ++ /* Force a clear before another dummy send */ ++ FIQ_WRITE(state->mphi_regs.intstat, (1<<29)); ++ FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send); ++ FIQ_WRITE(state->mphi_regs.outddb, (1<<29)); ++ ++ } ++ state->fiq_done++; ++ mb(); ++} +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h +new file mode 100644 +index 0000000..7572958 +--- /dev/null ++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h +@@ -0,0 +1,353 @@ ++/* ++ * dwc_otg_fiq_fsm.h - Finite state machine FIQ header definitions ++ * ++ * Copyright (c) 2013 Raspberry Pi Foundation ++ * ++ * Author: Jonathan Bell ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Raspberry Pi nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This FIQ implements functionality that performs split transactions on ++ * the dwc_otg hardware without any outside intervention. A split transaction ++ * is "queued" by nominating a specific host channel to perform the entirety ++ * of a split transaction. This FIQ will then perform the microframe-precise ++ * scheduling required in each phase of the transaction until completion. ++ * ++ * The FIQ functionality has been surgically implanted into the Synopsys ++ * vendor-provided driver. ++ * ++ */ ++ ++#ifndef DWC_OTG_FIQ_FSM_H_ ++#define DWC_OTG_FIQ_FSM_H_ ++ ++#include "dwc_otg_regs.h" ++#include "dwc_otg_cil.h" ++#include "dwc_otg_hcd.h" ++#include ++#include ++#include ++#include ++ ++#if 0 ++#define FLAME_ON(x) \ ++do { \ ++ int gpioreg; \ ++ \ ++ gpioreg = readl(__io_address(0x20200000+0x8)); \ ++ gpioreg &= ~(7 << (x-20)*3); \ ++ gpioreg |= 0x1 << (x-20)*3; \ ++ writel(gpioreg, __io_address(0x20200000+0x8)); \ ++ \ ++ writel(1< 1, SOF wakes up the isochronous FSM */ ++ FIQ_HS_ISOC_SLEEPING = 24, ++ FIQ_HS_ISOC_DONE = 25, ++ FIQ_HS_ISOC_ABORTED = 26, ++ FIQ_DEQUEUE_ISSUED = 30, ++ FIQ_TEST = 32, ++}; ++ ++struct fiq_stack { ++ int magic1; ++ uint8_t stack[2048]; ++ int magic2; ++}; ++ ++ ++/** ++ * struct fiq_dma_info - DMA bounce buffer utilisation information (per-channel) ++ * @index: Number of slots reported used for IN transactions / number of slots ++ * transmitted for an OUT transaction ++ * @slot_len[6]: Number of actual transfer bytes in each slot (255 if unused) ++ * ++ * Split transaction transfers can have variable length depending on other bus ++ * traffic. The OTG core DMA engine requires 4-byte aligned addresses therefore ++ * each transaction needs a guaranteed aligned address. A maximum of 6 split transfers ++ * can happen per-frame. ++ */ ++struct fiq_dma_info { ++ u8 index; ++ u8 slot_len[6]; ++}; ++ ++struct __attribute__((packed)) fiq_split_dma_slot { ++ u8 buf[188]; ++}; ++ ++struct fiq_dma_channel { ++ struct __attribute__((packed)) fiq_split_dma_slot index[6]; ++}; ++ ++struct fiq_dma_blob { ++ struct __attribute__((packed)) fiq_dma_channel channel[0]; ++}; ++ ++/** ++ * struct fiq_hs_isoc_info - USB2.0 isochronous data ++ * @iso_frame: Pointer to the array of OTG URB iso_frame_descs. ++ * @nrframes: Total length of iso_frame_desc array ++ * @index: Current index (FIQ-maintained) ++ * ++ */ ++struct fiq_hs_isoc_info { ++ struct dwc_otg_hcd_iso_packet_desc *iso_desc; ++ unsigned int nrframes; ++ unsigned int index; ++}; ++ ++/** ++ * struct fiq_channel_state - FIQ state machine storage ++ * @fsm: Current state of the channel as understood by the FIQ ++ * @nr_errors: Number of transaction errors on this split-transaction ++ * @hub_addr: SSPLIT/CSPLIT destination hub ++ * @port_addr: SSPLIT/CSPLIT destination port - always 1 if single TT hub ++ * @nrpackets: For isoc OUT, the number of split-OUT packets to transmit. For ++ * split-IN, number of CSPLIT data packets that were received. ++ * @hcchar_copy: ++ * @hcsplt_copy: ++ * @hcintmsk_copy: ++ * @hctsiz_copy: Copies of the host channel registers. ++ * For use as scratch, or for returning state. ++ * ++ * The fiq_channel_state is state storage between interrupts for a host channel. The ++ * FSM state is stored here. Members of this structure must only be set up by the ++ * driver prior to enabling the FIQ for this host channel, and not touched until the FIQ ++ * has updated the state to either a COMPLETE state group or ABORT state group. ++ */ ++ ++struct fiq_channel_state { ++ enum fiq_fsm_state fsm; ++ unsigned int nr_errors; ++ unsigned int hub_addr; ++ unsigned int port_addr; ++ /* Hardware bug workaround: sometimes channel halt interrupts are ++ * delayed until the next SOF. Keep track of when we expected to get interrupted. */ ++ unsigned int expected_uframe; ++ /* in/out for communicating number of dma buffers used, or number of ISOC to do */ ++ unsigned int nrpackets; ++ struct fiq_dma_info dma_info; ++ struct fiq_hs_isoc_info hs_isoc_info; ++ /* Copies of HC registers - in/out communication from/to IRQ handler ++ * and for ease of channel setup. A bit of mungeing is performed - for ++ * example the hctsiz.b.maxp is _always_ the max packet size of the endpoint. ++ */ ++ hcchar_data_t hcchar_copy; ++ hcsplt_data_t hcsplt_copy; ++ hcint_data_t hcint_copy; ++ hcintmsk_data_t hcintmsk_copy; ++ hctsiz_data_t hctsiz_copy; ++ hcdma_data_t hcdma_copy; ++}; ++ ++/** ++ * struct fiq_state - top-level FIQ state machine storage ++ * @mphi_regs: virtual address of the MPHI peripheral register file ++ * @dwc_regs_base: virtual address of the base of the DWC core register file ++ * @dma_base: physical address for the base of the DMA bounce buffers ++ * @dummy_send: Scratch area for sending a fake message to the MPHI peripheral ++ * @gintmsk_saved: Top-level mask of interrupts that the FIQ has not handled. ++ * Used for determining which interrupts fired to set off the IRQ handler. ++ * @haintmsk_saved: Mask of interrupts from host channels that the FIQ did not handle internally. ++ * @np_count: Non-periodic transactions in the active queue ++ * @np_sent: Count of non-periodic transactions that have completed ++ * @next_sched_frame: For periodic transactions handled by the driver's SOF-driven queuing mechanism, ++ * this is the next frame on which a SOF interrupt is required. Used to hold off ++ * passing SOF through to the driver until necessary. ++ * @channel[n]: Per-channel FIQ state. Allocated during init depending on the number of host ++ * channels configured into the core logic. ++ * ++ * This is passed as the first argument to the dwc_otg_fiq_fsm top-level FIQ handler from the asm stub. ++ * It contains top-level state information. ++ */ ++struct fiq_state { ++ mphi_regs_t mphi_regs; ++ void *dwc_regs_base; ++ dma_addr_t dma_base; ++ struct fiq_dma_blob *fiq_dmab; ++ void *dummy_send; ++ gintmsk_data_t gintmsk_saved; ++ haintmsk_data_t haintmsk_saved; ++ int mphi_int_count; ++ unsigned int fiq_done; ++ unsigned int kick_np_queues; ++ unsigned int next_sched_frame; ++#ifdef FIQ_DEBUG ++ char * buffer; ++ unsigned int bufsiz; ++#endif ++ struct fiq_channel_state channel[0]; ++}; ++ ++extern int fiq_fsm_too_late(struct fiq_state *st, int n); ++ ++extern int fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n); ++ ++extern void dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels); ++ ++extern void dwc_otg_fiq_nop(struct fiq_state *state); ++ ++#endif /* DWC_OTG_FIQ_FSM_H_ */ +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S b/drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S +new file mode 100644 +index 0000000..8cfe364 +--- /dev/null ++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S +@@ -0,0 +1,81 @@ ++/* ++ * dwc_otg_fiq_fsm.S - assembly stub for the FSM FIQ ++ * ++ * Copyright (c) 2013 Raspberry Pi Foundation ++ * ++ * Author: Jonathan Bell ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Raspberry Pi nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include ++#include ++ ++ ++.text ++ ++.global _dwc_otg_fiq_stub_end; ++ ++/** ++ * _dwc_otg_fiq_stub() - entry copied to the FIQ vector page to allow ++ * a C-style function call with arguments from the FIQ banked registers. ++ * r0 = &hcd->fiq_state ++ * r1 = &hcd->num_channels ++ * r2 = &hcd->dma_buffers ++ * Tramples: r0, r1, r2, r4, fp, ip ++ */ ++ ++ENTRY(_dwc_otg_fiq_stub) ++ /* Stash unbanked regs - SP will have been set up for us */ ++ mov ip, sp; ++ stmdb sp!, {r0-r12, lr}; ++#ifdef FIQ_DEBUG ++ // Cycle profiling - read cycle counter at start ++ mrc p15, 0, r5, c15, c12, 1; ++#endif ++ /* r11 = fp, don't trample it */ ++ mov r4, fp; ++ /* set EABI frame size */ ++ sub fp, ip, #512; ++ ++ /* for fiq NOP mode - just need state */ ++ mov r0, r8; ++ /* r9 = num_channels */ ++ mov r1, r9; ++ /* r10 = struct *dma_bufs */ ++// mov r2, r10; ++ ++ /* r4 = &fiq_c_function */ ++ blx r4; ++#ifdef FIQ_DEBUG ++ mrc p15, 0, r4, c15, c12, 1; ++ subs r5, r5, r4; ++ // r5 is now the cycle count time for executing the FIQ. Store it somewhere? ++#endif ++ ldmia sp!, {r0-r12, lr}; ++ subs pc, lr, #4; ++_dwc_otg_fiq_stub_end: ++END(_dwc_otg_fiq_stub) ++ +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +index 22300f0..daea770 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +@@ -45,9 +45,10 @@ + + #include "dwc_otg_hcd.h" + #include "dwc_otg_regs.h" +-#include "dwc_otg_mphi_fix.h" ++#include "dwc_otg_fiq_fsm.h" + +-extern bool microframe_schedule, nak_holdoff_enable; ++extern bool microframe_schedule; ++extern uint16_t fiq_fsm_mask, nak_holdoff; + + //#define DEBUG_HOST_CHANNELS + #ifdef DEBUG_HOST_CHANNELS +@@ -57,12 +58,6 @@ static int last_sel_trans_num_avail_hc_at_start = 0; + static int last_sel_trans_num_avail_hc_at_end = 0; + #endif /* DEBUG_HOST_CHANNELS */ + +-extern int g_next_sched_frame, g_np_count, g_np_sent; +- +-extern haint_data_t haint_saved; +-extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; +-extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; +-extern gintsts_data_t ginsts_saved; + + dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) + { +@@ -295,7 +290,7 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) + */ + dwc_otg_hcd->flags.b.port_connect_status_change = 1; + dwc_otg_hcd->flags.b.port_connect_status = 0; +- if(fiq_fix_enable) ++ if(fiq_enable) + local_fiq_disable(); + /* + * Shutdown any transfers in process by clearing the Tx FIFO Empty +@@ -392,20 +387,15 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) + channel->qh = NULL; + } + } +- if(fiq_split_enable) { ++ if(fiq_fsm_enable) { + for(i=0; i < 128; i++) { + dwc_otg_hcd->hub_port[i] = 0; + } +- haint_saved.d32 = 0; +- for(i=0; i < MAX_EPS_CHANNELS; i++) { +- hcint_saved[i].d32 = 0; +- hcintmsk_saved[i].d32 = 0; +- } + } + + } + +- if(fiq_fix_enable) ++ if(fiq_enable) + local_fiq_enable(); + + if (dwc_otg_hcd->fops->disconnect) { +@@ -542,7 +532,7 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, + } + #endif + intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); +- if(!intr_mask.b.sofintr) needs_scheduling = 1; ++ if(!intr_mask.b.sofintr || fiq_enable) needs_scheduling = 1; + if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) + /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */ + needs_scheduling = 0; +@@ -613,6 +603,7 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, + if (urb_qtd->in_process && qh->channel) { + /* The QTD is in process (it has been assigned to a channel). */ + if (hcd->flags.b.port_connect_status) { ++ int n = qh->channel->hc_num; + /* + * If still connected (i.e. in host mode), halt the + * channel so it can be used for other transfers. If +@@ -620,10 +611,16 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, + * written to halt the channel since the core is in + * device mode. + */ +- dwc_otg_hc_halt(hcd->core_if, qh->channel, +- DWC_OTG_HC_XFER_URB_DEQUEUE); +- +- dwc_otg_hcd_release_port(hcd, qh); ++ /* In FIQ FSM mode, we need to shut down carefully. ++ * The FIQ may attempt to restart a disabled channel */ ++ if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) { ++ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE; ++ qh->channel->halt_pending = 1; ++ hcd->fiq_state->channel[n].fsm = FIQ_DEQUEUE_ISSUED; ++ } else { ++ dwc_otg_hc_halt(hcd->core_if, qh->channel, ++ DWC_OTG_HC_XFER_URB_DEQUEUE); ++ } + } + } + +@@ -759,7 +756,6 @@ static void completion_tasklet_func(void *ptr) + + usb_hcd_giveback_urb(hcd->priv, urb, urb->status); + +- fiq_print(FIQDBG_PORTHUB, "COMPLETE"); + + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + } +@@ -854,6 +850,34 @@ void dwc_otg_hcd_power_up(void *ptr) + cil_hcd_start(core_if); + } + ++void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num) ++{ ++ struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; ++ struct fiq_dma_blob *blob = hcd->fiq_dmab; ++ int i; ++ ++ st->fsm = FIQ_PASSTHROUGH; ++ st->hcchar_copy.d32 = 0; ++ st->hcsplt_copy.d32 = 0; ++ st->hcint_copy.d32 = 0; ++ st->hcintmsk_copy.d32 = 0; ++ st->hctsiz_copy.d32 = 0; ++ st->hcdma_copy.d32 = 0; ++ st->nr_errors = 0; ++ st->hub_addr = 0; ++ st->port_addr = 0; ++ st->expected_uframe = 0; ++ st->nrpackets = 0; ++ st->dma_info.index = 0; ++ for (i = 0; i < 6; i++) ++ st->dma_info.slot_len[i] = 255; ++ st->hs_isoc_info.index = 0; ++ st->hs_isoc_info.iso_desc = NULL; ++ st->hs_isoc_info.nrframes = 0; ++ ++ DWC_MEMSET(&blob->channel[num].index[0], 0x6b, 1128); ++} ++ + /** + * Frees secondary storage associated with the dwc_otg_hcd structure contained + * in the struct usb_hcd field. +@@ -907,6 +931,7 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer); + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet); + DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet); ++ DWC_FREE(dwc_otg_hcd->fiq_state); + + #ifdef DWC_DEV_SRPCAP + if (dwc_otg_hcd->core_if->power_down == 2 && +@@ -979,6 +1004,59 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) + channel); + } + ++ if (fiq_enable) { ++ hcd->fiq_state = DWC_ALLOC(sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels)); ++ if (!hcd->fiq_state) { ++ retval = -DWC_E_NO_MEMORY; ++ DWC_ERROR("%s: cannot allocate fiq_state structure\n", __func__); ++ dwc_otg_hcd_free(hcd); ++ goto out; ++ } ++ DWC_MEMSET(hcd->fiq_state, 0, (sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels))); ++ ++ for (i = 0; i < num_channels; i++) { ++ hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH; ++ } ++ hcd->fiq_state->dummy_send = DWC_ALLOC_ATOMIC(16); ++ ++ hcd->fiq_stack = DWC_ALLOC(sizeof(struct fiq_stack)); ++ if (!hcd->fiq_stack) { ++ retval = -DWC_E_NO_MEMORY; ++ DWC_ERROR("%s: cannot allocate fiq_stack structure\n", __func__); ++ dwc_otg_hcd_free(hcd); ++ goto out; ++ } ++ hcd->fiq_stack->magic1 = 0xDEADBEEF; ++ hcd->fiq_stack->magic2 = 0xD00DFEED; ++ hcd->fiq_state->gintmsk_saved.d32 = ~0; ++ hcd->fiq_state->haintmsk_saved.b2.chint = ~0; ++ ++ /* This bit is terrible and uses no API, but necessary. The FIQ has no concept of DMA pools ++ * (and if it did, would be a lot slower). This allocates a chunk of memory (~9kiB for 8 host channels) ++ * for use as transaction bounce buffers in a 2-D array. Our access into this chunk is done by some ++ * moderately readable array casts. ++ */ ++ hcd->fiq_dmab = DWC_DMA_ALLOC((sizeof(struct fiq_dma_channel) * num_channels), &hcd->fiq_state->dma_base); ++ DWC_WARN("FIQ DMA bounce buffers: virt = 0x%08x dma = 0x%08x len=%d", ++ (unsigned int)hcd->fiq_dmab, (unsigned int)hcd->fiq_state->dma_base, ++ sizeof(struct fiq_dma_channel) * num_channels); ++ ++ DWC_MEMSET(hcd->fiq_dmab, 0x6b, 9024); ++ ++ /* pointer for debug in fiq_print */ ++ hcd->fiq_state->fiq_dmab = hcd->fiq_dmab; ++ if (fiq_fsm_enable) { ++ int i; ++ for (i=0; i < hcd->core_if->core_params->host_channels; i++) { ++ dwc_otg_cleanup_fiq_channel(hcd, i); ++ } ++ DWC_PRINTF("FIQ FSM acceleration enabled for :\n%s%s%s", ++ (fiq_fsm_mask & 0x1) ? "Non-periodic Split Transactions\n" : "", ++ (fiq_fsm_mask & 0x2) ? "Periodic Split Transactions\n" : "", ++ (fiq_fsm_mask & 0x4) ? "High-Speed Isochronous Endpoints\n" : ""); ++ } ++ } ++ + /* Initialize the Connection timeout timer. */ + hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer", + dwc_otg_hcd_connect_timeout, 0); +@@ -1176,7 +1254,8 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + hc->do_split = 1; + hc->xact_pos = qtd->isoc_split_pos; + /* We don't need to do complete splits anymore */ +- if(fiq_split_enable) ++// if(fiq_fsm_enable) ++ if (0) + hc->complete_split = qtd->complete_split = 0; + else + hc->complete_split = qtd->complete_split; +@@ -1327,62 +1406,487 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + hc->qh = qh; + } + +-/* +-** Check the transaction to see if the port / hub has already been assigned for +-** a split transaction +-** +-** Return 0 - Port is already in use +-*/ +-int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) ++ ++/** ++ * fiq_fsm_transaction_suitable() - Test a QH for compatibility with the FIQ ++ * @qh: pointer to the endpoint's queue head ++ * ++ * Transaction start/end control flow is grafted onto the existing dwc_otg ++ * mechanisms, to avoid spaghettifying the functions more than they already are. ++ * This function's eligibility check is altered by debug parameter. ++ * ++ * Returns: 0 for unsuitable, 1 implies the FIQ can be enabled for this transaction. ++ */ ++ ++int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh) + { +- uint32_t hub_addr, port_addr; ++ if (qh->do_split) { ++ switch (qh->ep_type) { ++ case UE_CONTROL: ++ case UE_BULK: ++ if (fiq_fsm_mask & (1 << 0)) ++ return 1; ++ break; ++ case UE_INTERRUPT: ++ case UE_ISOCHRONOUS: ++ if (fiq_fsm_mask & (1 << 1)) ++ return 1; ++ break; ++ default: ++ break; ++ } ++ } else if (qh->ep_type == UE_ISOCHRONOUS) { ++ if (fiq_fsm_mask & (1 << 2)) { ++ /* HS ISOCH support. We test for compatibility: ++ * - DWORD aligned buffers ++ * - Must be at least 2 transfers (otherwise pointless to use the FIQ) ++ * If yes, then the fsm enqueue function will handle the state machine setup. ++ */ ++ dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); ++ dwc_otg_hcd_urb_t *urb = qtd->urb; ++ struct dwc_otg_hcd_iso_packet_desc (*iso_descs)[0] = &urb->iso_descs; ++ int nr_iso_frames = urb->packet_count; ++ int i; ++ uint32_t ptr; ++ ++ if (nr_iso_frames < 2) ++ return 0; ++ for (i = 0; i < nr_iso_frames; i++) { ++ ptr = urb->dma + iso_descs[i]->offset; ++ if (ptr & 0x3) { ++ printk_ratelimited("%s: Non-Dword aligned isochronous frame offset." ++ " Cannot queue FIQ-accelerated transfer to device %d endpoint %d\n", ++ __FUNCTION__, qh->channel->dev_addr, qh->channel->ep_num); ++ return 0; ++ } ++ } ++ return 1; ++ } ++ } ++ return 0; ++} + +- if(!fiq_split_enable) +- return 0; ++/** ++ * fiq_fsm_setup_periodic_dma() - Set up DMA bounce buffers ++ * @hcd: Pointer to the dwc_otg_hcd struct ++ * @qh: Pointer to the endpoint's queue head ++ * ++ * Periodic split transactions are transmitted modulo 188 bytes. ++ * This necessitates slicing data up into buckets for isochronous out ++ * and fixing up the DMA address for all IN transfers. ++ * ++ * Returns 1 if the DMA bounce buffers have been used, 0 if the default ++ * HC buffer has been used. ++ */ ++int fiq_fsm_setup_periodic_dma(dwc_otg_hcd_t *hcd, struct fiq_channel_state *st, dwc_otg_qh_t *qh) ++ { ++ int frame_length, i = 0; ++ uint8_t *ptr = NULL; ++ dwc_hc_t *hc = qh->channel; ++ struct fiq_dma_blob *blob; ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc; ++ ++ for (i = 0; i < 6; i++) { ++ st->dma_info.slot_len[i] = 255; ++ } ++ st->dma_info.index = 0; ++ i = 0; ++ if (hc->ep_is_in) { ++ /* ++ * Set dma_regs to bounce buffer. FIQ will update the ++ * state depending on transaction progress. ++ */ ++ blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base; ++ st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0]; ++ /* Calculate the max number of CSPLITS such that the FIQ can time out ++ * a transaction if it fails. ++ */ ++ frame_length = st->hcchar_copy.b.mps; ++ do { ++ i++; ++ frame_length -= 188; ++ } while (frame_length >= 0); ++ st->nrpackets = i; ++ return 1; ++ } else { ++ if (qh->ep_type == UE_ISOCHRONOUS) { + +- hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); ++ dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); + +- if(hcd->hub_port[hub_addr] & (1 << port_addr)) +- { +- fiq_print(FIQDBG_PORTHUB, "H%dP%d:S%02d", hub_addr, port_addr, qh->skip_count); ++ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; ++ frame_length = frame_desc->length; + +- qh->skip_count++; ++ /* Virtual address for bounce buffers */ ++ blob = hcd->fiq_dmab; + +- if(qh->skip_count > 40000) +- { +- printk_once(KERN_ERR "Error: Having to skip port allocation"); +- local_fiq_disable(); +- BUG(); ++ ptr = qtd->urb->buf + frame_desc->offset; ++ if (frame_length == 0) { ++ /* ++ * for isochronous transactions, we must still transmit a packet ++ * even if the length is zero. ++ */ ++ st->dma_info.slot_len[0] = 0; ++ st->nrpackets = 1; ++ } else { ++ do { ++ if (frame_length <= 188) { ++ dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, frame_length); ++ st->dma_info.slot_len[i] = frame_length; ++ ptr += frame_length; ++ } else { ++ dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, 188); ++ st->dma_info.slot_len[i] = 188; ++ ptr += 188; ++ } ++ i++; ++ frame_length -= 188; ++ } while (frame_length > 0); ++ st->nrpackets = i; ++ } ++ ptr = qtd->urb->buf + frame_desc->offset; ++ /* Point the HC at the DMA address of the bounce buffers */ ++ blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base; ++ st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0]; ++ ++ /* fixup xfersize to the actual packet size */ ++ st->hctsiz_copy.b.pid = 0; ++ st->hctsiz_copy.b.xfersize = st->dma_info.slot_len[0]; ++ return 1; ++ } else { ++ /* For interrupt, single OUT packet required, goes in the SSPLIT from hc_buff. */ + return 0; + } +- return 1; + } +- else +- { +- qh->skip_count = 0; +- hcd->hub_port[hub_addr] |= 1 << port_addr; +- fiq_print(FIQDBG_PORTHUB, "H%dP%d:A %d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); +-#ifdef FIQ_DEBUG +- hcd->hub_port_alloc[hub_addr * 16 + port_addr] = dwc_otg_hcd_get_frame_number(hcd); +-#endif ++} ++ ++/* ++ * Pushing a periodic request into the queue near the EOF1 point ++ * in a microframe causes erroneous behaviour (frmovrun) interrupt. ++ * Usually, the request goes out on the bus causing a transfer but ++ * the core does not transfer the data to memory. ++ * This guard interval (in number of 60MHz clocks) is required which ++ * must cater for CPU latency between reading the value and enabling ++ * the channel. ++ */ ++#define PERIODIC_FRREM_BACKOFF 1000 ++ ++int fiq_fsm_queue_isoc_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) ++{ ++ dwc_hc_t *hc = qh->channel; ++ dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; ++ dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); ++ int frame; ++ struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num]; ++ int xfer_len, nrpackets; ++ hcdma_data_t hcdma; ++ hfnum_data_t hfnum; ++ ++ if (st->fsm != FIQ_PASSTHROUGH) + return 0; ++ ++ st->nr_errors = 0; ++ ++ st->hcchar_copy.d32 = 0; ++ st->hcchar_copy.b.mps = hc->max_packet; ++ st->hcchar_copy.b.epdir = hc->ep_is_in; ++ st->hcchar_copy.b.devaddr = hc->dev_addr; ++ st->hcchar_copy.b.epnum = hc->ep_num; ++ st->hcchar_copy.b.eptype = hc->ep_type; ++ ++ st->hcintmsk_copy.b.chhltd = 1; ++ ++ frame = dwc_otg_hcd_get_frame_number(hcd); ++ st->hcchar_copy.b.oddfrm = (frame & 0x1) ? 0 : 1; ++ ++ st->hcchar_copy.b.lspddev = 0; ++ /* Enable the channel later as a final register write. */ ++ ++ st->hcsplt_copy.d32 = 0; ++ ++ st->hs_isoc_info.iso_desc = (struct dwc_otg_hcd_iso_packet_desc *) &qtd->urb->iso_descs; ++ st->hs_isoc_info.nrframes = qtd->urb->packet_count; ++ /* grab the next DMA address offset from the array */ ++ st->hcdma_copy.d32 = qtd->urb->dma; ++ hcdma.d32 = st->hcdma_copy.d32 + st->hs_isoc_info.iso_desc[0].offset; ++ ++ /* We need to set multi_count. This is a bit tricky - has to be set per-transaction as ++ * the core needs to be told to send the correct number. Caution: for IN transfers, ++ * this is always set to the maximum size of the endpoint. */ ++ xfer_len = st->hs_isoc_info.iso_desc[0].length; ++ nrpackets = (xfer_len + st->hcchar_copy.b.mps - 1) / st->hcchar_copy.b.mps; ++ if (nrpackets == 0) ++ nrpackets = 1; ++ st->hcchar_copy.b.multicnt = nrpackets; ++ st->hctsiz_copy.b.pktcnt = nrpackets; ++ ++ /* Initial PID also needs to be set */ ++ if (st->hcchar_copy.b.epdir == 0) { ++ st->hctsiz_copy.b.xfersize = xfer_len; ++ switch (st->hcchar_copy.b.multicnt) { ++ case 1: ++ st->hctsiz_copy.b.pid = DWC_PID_DATA0; ++ break; ++ case 2: ++ case 3: ++ st->hctsiz_copy.b.pid = DWC_PID_MDATA; ++ break; ++ } ++ ++ } else { ++ st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps; ++ switch (st->hcchar_copy.b.multicnt) { ++ case 1: ++ st->hctsiz_copy.b.pid = DWC_PID_DATA0; ++ break; ++ case 2: ++ st->hctsiz_copy.b.pid = DWC_PID_DATA1; ++ break; ++ case 3: ++ st->hctsiz_copy.b.pid = DWC_PID_DATA2; ++ break; ++ } + } ++ ++ fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d ", hc->hc_num); ++ fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcchar_copy.d32); ++ fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32); ++ fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32); ++ hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); ++ local_fiq_disable(); ++ DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32); ++ DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32); ++ DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32); ++ DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); ++ DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32); ++ if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) { ++ /* Prevent queueing near EOF1. Bad things happen if a periodic ++ * split transaction is queued very close to EOF. ++ */ ++ st->fsm = FIQ_HS_ISOC_SLEEPING; ++ } else { ++ st->fsm = FIQ_HS_ISOC_TURBO; ++ st->hcchar_copy.b.chen = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); ++ } ++ mb(); ++ st->hcchar_copy.b.chen = 0; ++ local_fiq_enable(); ++ return 0; + } +-void dwc_otg_hcd_release_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) ++ ++ ++/** ++ * fiq_fsm_queue_split_transaction() - Set up a host channel and FIQ state ++ * @hcd: Pointer to the dwc_otg_hcd struct ++ * @qh: Pointer to the endpoint's queue head ++ * ++ * This overrides the dwc_otg driver's normal method of queueing a transaction. ++ * Called from dwc_otg_hcd_queue_transactions(), this performs specific setup ++ * for the nominated host channel. ++ * ++ * For periodic transfers, it also peeks at the FIQ state to see if an immediate ++ * start is possible. If not, then the FIQ is left to start the transfer. ++ */ ++int fiq_fsm_queue_split_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) + { +- uint32_t hub_addr, port_addr; ++ int start_immediate = 1, i; ++ hfnum_data_t hfnum; ++ dwc_hc_t *hc = qh->channel; ++ dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; ++ /* Program HC registers, setup FIQ_state, examine FIQ if periodic, start transfer (not if uframe 5) */ ++ int hub_addr, port_addr, frame, uframe; ++ struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num]; + +- if(!fiq_split_enable) +- return; ++ if (st->fsm != FIQ_PASSTHROUGH) ++ return 0; ++ st->nr_errors = 0; ++ ++ st->hcchar_copy.d32 = 0; ++ st->hcchar_copy.b.mps = hc->max_packet; ++ st->hcchar_copy.b.epdir = hc->ep_is_in; ++ st->hcchar_copy.b.devaddr = hc->dev_addr; ++ st->hcchar_copy.b.epnum = hc->ep_num; ++ st->hcchar_copy.b.eptype = hc->ep_type; ++ if (hc->ep_type & 0x1) { ++ if (hc->ep_is_in) ++ st->hcchar_copy.b.multicnt = 3; ++ else ++ /* Docs say set this to 1, but driver sets to 0! */ ++ st->hcchar_copy.b.multicnt = 0; ++ } else { ++ st->hcchar_copy.b.multicnt = 1; ++ st->hcchar_copy.b.oddfrm = 0; ++ } ++ st->hcchar_copy.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW) ? 1 : 0; ++ /* Enable the channel later as a final register write. */ ++ ++ st->hcsplt_copy.d32 = 0; ++ if(qh->do_split) { ++ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); ++ st->hcsplt_copy.b.compsplt = 0; ++ st->hcsplt_copy.b.spltena = 1; ++ // XACTPOS is for isoc-out only but needs initialising anyway. ++ st->hcsplt_copy.b.xactpos = ISOC_XACTPOS_ALL; ++ if((qh->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!qh->ep_is_in)) { ++ /* For packetsize 0 < L < 188, ISOC_XACTPOS_ALL. ++ * for longer than this, ISOC_XACTPOS_BEGIN and the FIQ ++ * will update as necessary. ++ */ ++ if (hc->xfer_len > 188) { ++ st->hcsplt_copy.b.xactpos = ISOC_XACTPOS_BEGIN; ++ } ++ } ++ st->hcsplt_copy.b.hubaddr = (uint8_t) hub_addr; ++ st->hcsplt_copy.b.prtaddr = (uint8_t) port_addr; ++ st->hub_addr = hub_addr; ++ st->port_addr = port_addr; ++ } + +- hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); ++ st->hctsiz_copy.d32 = 0; ++ st->hctsiz_copy.b.dopng = 0; ++ st->hctsiz_copy.b.pid = hc->data_pid_start; + +- hcd->hub_port[hub_addr] &= ~(1 << port_addr); +-#ifdef FIQ_DEBUG +- hcd->hub_port_alloc[hub_addr * 16 + port_addr] = -1; +-#endif +- fiq_print(FIQDBG_PORTHUB, "H%dP%d:RO%d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); ++ if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) { ++ hc->xfer_len = hc->max_packet; ++ } else if (!hc->ep_is_in && (hc->xfer_len > 188)) { ++ hc->xfer_len = 188; ++ } ++ st->hctsiz_copy.b.xfersize = hc->xfer_len; ++ ++ st->hctsiz_copy.b.pktcnt = 1; + ++ if (hc->ep_type & 0x1) { ++ /* ++ * For potentially multi-packet transfers, must use the DMA bounce buffers. For IN transfers, ++ * the DMA address is the address of the first 188byte slot buffer in the bounce buffer array. ++ * For multi-packet OUT transfers, we need to copy the data into the bounce buffer array so the FIQ can punt ++ * the right address out as necessary. hc->xfer_buff and hc->xfer_len have already been set ++ * in assign_and_init_hc(), but this is for the eventual transaction completion only. The FIQ ++ * must not touch internal driver state. ++ */ ++ if(!fiq_fsm_setup_periodic_dma(hcd, st, qh)) { ++ if (hc->align_buff) { ++ st->hcdma_copy.d32 = hc->align_buff; ++ } else { ++ st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); ++ } ++ } ++ } else { ++ if (hc->align_buff) { ++ st->hcdma_copy.d32 = hc->align_buff; ++ } else { ++ st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); ++ } ++ } ++ /* The FIQ depends upon no other interrupts being enabled except channel halt. ++ * Fixup channel interrupt mask. */ ++ st->hcintmsk_copy.d32 = 0; ++ st->hcintmsk_copy.b.chhltd = 1; ++ st->hcintmsk_copy.b.ahberr = 1; ++ ++ DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32); ++ DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32); ++ DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32); ++ DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); ++ DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32); ++ ++ local_fiq_disable(); ++ mb(); ++ ++ if (hc->ep_type & 0x1) { ++ hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); ++ frame = (hfnum.b.frnum & ~0x7) >> 3; ++ uframe = hfnum.b.frnum & 0x7; ++ if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) { ++ /* Prevent queueing near EOF1. Bad things happen if a periodic ++ * split transaction is queued very close to EOF. ++ */ ++ start_immediate = 0; ++ } else if (uframe == 5) { ++ start_immediate = 0; ++ } else if (hc->ep_type == UE_ISOCHRONOUS && !hc->ep_is_in) { ++ start_immediate = 0; ++ } else if (hc->ep_is_in && fiq_fsm_too_late(hcd->fiq_state, hc->hc_num)) { ++ start_immediate = 0; ++ } else { ++ /* Search through all host channels to determine if a transaction ++ * is currently in progress */ ++ for (i = 0; i < hcd->core_if->core_params->host_channels; i++) { ++ if (i == hc->hc_num || hcd->fiq_state->channel[i].fsm == FIQ_PASSTHROUGH) ++ continue; ++ switch (hcd->fiq_state->channel[i].fsm) { ++ /* TT is reserved for channels that are in the middle of a periodic ++ * split transaction. ++ */ ++ case FIQ_PER_SSPLIT_STARTED: ++ case FIQ_PER_CSPLIT_WAIT: ++ case FIQ_PER_CSPLIT_NYET1: ++ case FIQ_PER_CSPLIT_POLL: ++ case FIQ_PER_ISO_OUT_ACTIVE: ++ case FIQ_PER_ISO_OUT_LAST: ++ if (hcd->fiq_state->channel[i].hub_addr == hub_addr && ++ hcd->fiq_state->channel[i].port_addr == port_addr) { ++ start_immediate = 0; ++ } ++ break; ++ default: ++ break; ++ } ++ if (!start_immediate) ++ break; ++ } ++ } ++ } ++ fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d %01d", hc->hc_num, start_immediate); ++ fiq_print(FIQDBG_INT, hcd->fiq_state, "%08d", hfnum.b.frrem); ++ //fiq_print(FIQDBG_INT, hcd->fiq_state, "H:%02dP:%02d", hub_addr, port_addr); ++ //fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32); ++ //fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32); ++ switch (hc->ep_type) { ++ case UE_CONTROL: ++ case UE_BULK: ++ st->fsm = FIQ_NP_SSPLIT_STARTED; ++ break; ++ case UE_ISOCHRONOUS: ++ if (hc->ep_is_in) { ++ if (start_immediate) { ++ st->fsm = FIQ_PER_SSPLIT_STARTED; ++ } else { ++ st->fsm = FIQ_PER_SSPLIT_QUEUED; ++ } ++ } else { ++ if (start_immediate) { ++ /* Single-isoc OUT packets don't require FIQ involvement */ ++ if (st->nrpackets == 1) { ++ st->fsm = FIQ_PER_ISO_OUT_LAST; ++ } else { ++ st->fsm = FIQ_PER_ISO_OUT_ACTIVE; ++ } ++ } else { ++ st->fsm = FIQ_PER_ISO_OUT_PENDING; ++ } ++ } ++ break; ++ case UE_INTERRUPT: ++ if (start_immediate) { ++ st->fsm = FIQ_PER_SSPLIT_STARTED; ++ } else { ++ st->fsm = FIQ_PER_SSPLIT_QUEUED; ++ } ++ default: ++ break; ++ } ++ if (start_immediate) { ++ /* Set the oddfrm bit as close as possible to actual queueing */ ++ frame = dwc_otg_hcd_get_frame_number(hcd); ++ st->expected_uframe = (frame + 1) & 0x3FFF; ++ st->hcchar_copy.b.oddfrm = (frame & 0x1) ? 0 : 1; ++ st->hcchar_copy.b.chen = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); ++ } ++ mb(); ++ local_fiq_enable(); ++ return 0; + } + + +@@ -1399,16 +1903,11 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + { + dwc_list_link_t *qh_ptr; + dwc_otg_qh_t *qh; +- dwc_otg_qtd_t *qtd; + int num_channels; + dwc_irqflags_t flags; + dwc_spinlock_t *channel_lock = hcd->channel_lock; + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; + +-#ifdef DEBUG_SOF +- DWC_DEBUGPL(DBG_HCD, " Select Transactions\n"); +-#endif +- + #ifdef DEBUG_HOST_CHANNELS + last_sel_trans_num_per_scheduled = 0; + last_sel_trans_num_nonper_scheduled = 0; +@@ -1423,26 +1922,11 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); + +- if(qh->do_split) { +- qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); +- if(!(qh->ep_type == UE_ISOCHRONOUS && +- (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID || +- qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))) { +- if(dwc_otg_hcd_allocate_port(hcd, qh)) +- { +- qh_ptr = DWC_LIST_NEXT(qh_ptr); +- g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); +- continue; +- } +- } +- } +- + if (microframe_schedule) { + // Make sure we leave one channel for non periodic transactions. + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); + if (hcd->available_host_channels <= 1) { + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); +- if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh); + break; + } + hcd->available_host_channels--; +@@ -1478,27 +1962,24 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { + + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); +- + /* + * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission + * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed + * cheeky devices that just hold off using NAKs + */ +- if (nak_holdoff_enable && qh->do_split) { +- if (qh->nak_frame != 0xffff && +- dwc_full_frame_num(qh->nak_frame) == +- dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { +- /* +- * Revisit: Need to avoid trampling on periodic scheduling. +- * Currently we are safe because g_np_count != g_np_sent whenever we hit this, +- * but if this behaviour is changed then periodic endpoints will get a slower +- * polling rate. +- */ +- g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; +- qh_ptr = DWC_LIST_NEXT(qh_ptr); +- continue; +- } else { +- qh->nak_frame = 0xffff; ++ if (nak_holdoff && qh->do_split) { ++ if (qh->nak_frame != 0xffff) { ++ uint16_t next_frame = dwc_frame_num_inc(qh->nak_frame, (qh->ep_type == UE_BULK) ? nak_holdoff : 8); ++ uint16_t frame = dwc_otg_hcd_get_frame_number(hcd); ++ if (dwc_frame_num_le(frame, next_frame)) { ++ if(dwc_frame_num_le(next_frame, hcd->fiq_state->next_sched_frame)) { ++ hcd->fiq_state->next_sched_frame = next_frame; ++ } ++ qh_ptr = DWC_LIST_NEXT(qh_ptr); ++ continue; ++ } else { ++ qh->nak_frame = 0xFFFF; ++ } + } + } + +@@ -1527,12 +2008,31 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) + &qh->qh_list_entry); + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); + +- g_np_sent++; + + if (!microframe_schedule) + hcd->non_periodic_channels++; + } +- ++ /* we moved a non-periodic QH to the active schedule. If the inactive queue is empty, ++ * stop the FIQ from kicking us. We could potentially still have elements here if we ++ * ran out of host channels. ++ */ ++ if (fiq_enable) { ++ if (DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive)) { ++ hcd->fiq_state->kick_np_queues = 0; ++ } else { ++ /* For each entry remaining in the NP inactive queue, ++ * if this a NAK'd retransmit then don't set the kick flag. ++ */ ++ if(nak_holdoff) { ++ DWC_LIST_FOREACH(qh_ptr, &hcd->non_periodic_sched_inactive) { ++ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ if (qh->nak_frame == 0xFFFF) { ++ hcd->fiq_state->kick_np_queues = 1; ++ } ++ } ++ } ++ } ++ } + if(!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) + ret_val |= DWC_OTG_TRANSACTION_PERIODIC; + +@@ -1577,6 +2077,12 @@ static int queue_transaction(dwc_otg_hcd_t * hcd, + hc->qh->ping_state = 0; + } + } else if (!hc->xfer_started) { ++ if (fiq_fsm_enable && hc->error_state) { ++ hcd->fiq_state->channel[hc->hc_num].nr_errors = ++ DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list)->error_count; ++ hcd->fiq_state->channel[hc->hc_num].fsm = ++ FIQ_PASSTHROUGH_ERRORSTATE; ++ } + dwc_otg_hc_start_transfer(hcd->core_if, hc); + hc->qh->ping_state = 0; + } +@@ -1629,7 +2135,7 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) + hptxsts_data_t tx_status; + dwc_list_link_t *qh_ptr; + dwc_otg_qh_t *qh; +- int status; ++ int status = 0; + int no_queue_space = 0; + int no_fifo_space = 0; + +@@ -1658,27 +2164,34 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) + + // Do not send a split start transaction any later than frame .6 + // Note, we have to schedule a periodic in .5 to make it go in .6 +- if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) ++ if(fiq_fsm_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) + { + qh_ptr = qh_ptr->next; +- g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; ++ hcd->fiq_state->next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; + continue; + } + +- /* +- * Set a flag if we're queuing high-bandwidth in slave mode. +- * The flag prevents any halts to get into the request queue in +- * the middle of multiple high-bandwidth packets getting queued. +- */ +- if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) { +- hcd->core_if->queuing_high_bandwidth = 1; +- } +- status = +- queue_transaction(hcd, qh->channel, +- tx_status.b.ptxfspcavail); +- if (status < 0) { +- no_fifo_space = 1; +- break; ++ if (fiq_fsm_enable && fiq_fsm_transaction_suitable(qh)) { ++ if (qh->do_split) ++ fiq_fsm_queue_split_transaction(hcd, qh); ++ else ++ fiq_fsm_queue_isoc_transaction(hcd, qh); ++ } else { ++ ++ /* ++ * Set a flag if we're queueing high-bandwidth in slave mode. ++ * The flag prevents any halts to get into the request queue in ++ * the middle of multiple high-bandwidth packets getting queued. ++ */ ++ if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) { ++ hcd->core_if->queuing_high_bandwidth = 1; ++ } ++ status = queue_transaction(hcd, qh->channel, ++ tx_status.b.ptxfspcavail); ++ if (status < 0) { ++ no_fifo_space = 1; ++ break; ++ } + } + + /* +@@ -1795,25 +2308,19 @@ static void process_non_periodic_channels(dwc_otg_hcd_t * hcd) + qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t, + qh_list_entry); + +- // Do not send a split start transaction any later than frame .5 +- // non periodic transactions will start immediately in this uframe +- if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) +- { +- g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; +- break; +- } +- +- status = +- queue_transaction(hcd, qh->channel, +- tx_status.b.nptxfspcavail); ++ if(fiq_fsm_enable && fiq_fsm_transaction_suitable(qh)) { ++ fiq_fsm_queue_split_transaction(hcd, qh); ++ } else { ++ status = queue_transaction(hcd, qh->channel, ++ tx_status.b.nptxfspcavail); + +- if (status > 0) { +- more_to_do = 1; +- } else if (status < 0) { +- no_fifo_space = 1; +- break; ++ if (status > 0) { ++ more_to_do = 1; ++ } else if (status < 0) { ++ no_fifo_space = 1; ++ break; ++ } + } +- + /* Advance to next QH, skipping start-of-list entry. */ + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next; + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) { +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h +index 0007fa1..da2986244 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h +@@ -40,6 +40,8 @@ + #include "dwc_otg_core_if.h" + #include "dwc_list.h" + #include "dwc_otg_cil.h" ++#include "dwc_otg_fiq_fsm.h" ++ + + /** + * @file +@@ -585,6 +587,12 @@ struct dwc_otg_hcd { + /** Frame List DMA address */ + dma_addr_t frame_list_dma; + ++ struct fiq_stack *fiq_stack; ++ struct fiq_state *fiq_state; ++ ++ /** Virtual address for split transaction DMA bounce buffers */ ++ struct fiq_dma_blob *fiq_dmab; ++ + #ifdef DEBUG + uint32_t frrem_samples; + uint64_t frrem_accum; +@@ -615,6 +623,9 @@ extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, + int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh); + void dwc_otg_hcd_release_port(dwc_otg_hcd_t * dwc_otg_hcd, dwc_otg_qh_t *qh); + ++extern int fiq_fsm_queue_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh); ++extern int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh); ++extern void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num); + + /** @} */ + +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +index 64d33a5..d3e2035 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +@@ -34,7 +34,6 @@ + + #include "dwc_otg_hcd.h" + #include "dwc_otg_regs.h" +-#include "dwc_otg_mphi_fix.h" + + #include + #include +@@ -47,33 +46,8 @@ extern bool microframe_schedule; + * This file contains the implementation of the HCD Interrupt handlers. + */ + +-/* +- * Some globals to communicate between the FIQ and INTERRUPT +- */ +- +-void * dummy_send; +-mphi_regs_t c_mphi_regs; +-volatile void *dwc_regs_base; + int fiq_done, int_done; + +-gintsts_data_t gintsts_saved = {.d32 = 0}; +-hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; +-hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; +-int split_out_xfersize[MAX_EPS_CHANNELS]; +-haint_data_t haint_saved; +- +-int g_next_sched_frame, g_np_count, g_np_sent; +-static int mphi_int_count = 0 ; +- +-hcchar_data_t nak_hcchar; +-hctsiz_data_t nak_hctsiz; +-hcsplt_data_t nak_hcsplt; +-int nak_count; +- +-int complete_sched[MAX_EPS_CHANNELS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +-int split_start_frame[MAX_EPS_CHANNELS]; +-int queued_port[MAX_EPS_CHANNELS]; +- + #ifdef FIQ_DEBUG + char buffer[1000*16]; + int wptr; +@@ -83,12 +57,10 @@ void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) + va_list args; + char text[17]; + hfnum_data_t hfnum = { .d32 = FIQ_READ(dwc_regs_base + 0x408) }; +- unsigned long flags; + +- local_irq_save(flags); +- local_fiq_disable(); + if(dbg_lvl & dbg_lvl_req || dbg_lvl == FIQDBG_ERR) + { ++ local_fiq_disable(); + snprintf(text, 9, "%4d%d:%d ", hfnum.b.frnum/8, hfnum.b.frnum%8, 8 - hfnum.b.frrem/937); + va_start(args, fmt); + vsnprintf(text+8, 9, fmt, args); +@@ -96,410 +68,21 @@ void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) + + memcpy(buffer + wptr, text, 16); + wptr = (wptr + 16) % sizeof(buffer); ++ local_fiq_enable(); + } +- local_irq_restore(flags); + } + #endif + +-void notrace fiq_queue_request(int channel, int odd_frame) +-{ +- hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; +- hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; +- hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10) }; +- +- if(hcsplt.b.spltena == 0) +- { +- fiq_print(FIQDBG_ERR, "SPLTENA "); +- BUG(); +- } +- +- if(hcchar.b.epdir == 1) +- { +- fiq_print(FIQDBG_SCHED, "IN Ch %d", channel); +- } +- else +- { +- hctsiz.b.xfersize = 0; +- fiq_print(FIQDBG_SCHED, "OUT Ch %d", channel); +- } +- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x10), hctsiz.d32); +- +- hcsplt.b.compsplt = 1; +- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x4), hcsplt.d32); +- +- // Send the Split complete +- hcchar.b.chen = 1; +- hcchar.b.oddfrm = odd_frame ? 1 : 0; +- +- // Post this for transmit on the next frame for periodic or this frame for non-periodic +- fiq_print(FIQDBG_SCHED, "SND_%s", odd_frame ? "ODD " : "EVEN"); +- +- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x0), hcchar.d32); +-} +- +-static int last_sof = -1; +- +-/* +-** Function to handle the start of frame interrupt, choose whether we need to do anything and +-** therefore trigger the main interrupt +-** +-** returns int != 0 - interrupt has been handled +-*/ +-int diff; +- +-int notrace fiq_sof_handle(hfnum_data_t hfnum) +-{ +- int handled = 0; +- int i; +- +- // Just check that once we're running we don't miss a SOF +- /*if(last_sof != -1 && (hfnum.b.frnum != ((last_sof + 1) & 0x3fff))) +- { +- fiq_print(FIQDBG_ERR, "LASTSOF "); +- fiq_print(FIQDBG_ERR, "%4d%d ", last_sof / 8, last_sof & 7); +- fiq_print(FIQDBG_ERR, "%4d%d ", hfnum.b.frnum / 8, hfnum.b.frnum & 7); +- BUG(); +- }*/ +- +- // Only start remembering the last sof when the interrupt has been +- // enabled (we don't check the mask to come in here...) +- if(last_sof != -1 || FIQ_READ(dwc_regs_base + 0x18) & (1<<3)) +- last_sof = hfnum.b.frnum; +- +- for(i = 0; i < MAX_EPS_CHANNELS; i++) +- { +- if(complete_sched[i] != -1) +- { +- if(complete_sched[i] <= hfnum.b.frnum || (complete_sched[i] > 0x3f00 && hfnum.b.frnum < 0xf0)) +- { +- fiq_queue_request(i, hfnum.b.frnum & 1); +- complete_sched[i] = -1; +- } +- } +- +- if(complete_sched[i] != -1) +- { +- // This is because we've seen a split complete occur with no start... +- // most likely because missed the complete 0x3fff frames ago! +- +- diff = (hfnum.b.frnum + 0x3fff - complete_sched[i]) & 0x3fff ; +- if(diff > 32 && diff < 0x3f00) +- { +- fiq_print(FIQDBG_ERR, "SPLTMISS"); +- BUG(); +- } +- } +- } +- +- if(g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) +- { +- /* +- * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet +- * g_next_sched_frame is the next frame we have periodic packets for +- * +- * if neither of these are required for this frame then just clear the interrupt +- */ +- handled = 1; +- +- } +- +- return handled; +-} +- +-int notrace port_id(hcsplt_data_t hcsplt) +-{ +- return hcsplt.b.prtaddr + (hcsplt.b.hubaddr << 8); +-} +- +-int notrace fiq_hcintr_handle(int channel, hfnum_data_t hfnum) +-{ +- hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; +- hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; +- hcint_data_t hcint = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x8) }; +- hcintmsk_data_t hcintmsk = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0xc) }; +- hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10)}; +- +- hcint_saved[channel].d32 |= hcint.d32; +- hcintmsk_saved[channel].d32 = hcintmsk.d32; +- +- if(hcsplt.b.spltena) +- { +- fiq_print(FIQDBG_PORTHUB, "ph: %4x", port_id(hcsplt)); +- if(hcint.b.chhltd) +- { +- fiq_print(FIQDBG_SCHED, "CH HLT %d", channel); +- fiq_print(FIQDBG_SCHED, "%08x", hcint_saved[channel]); +- } +- if(hcint.b.stall || hcint.b.xacterr || hcint.b.bblerr || hcint.b.frmovrun || hcint.b.datatglerr) +- { +- queued_port[channel] = 0; +- fiq_print(FIQDBG_ERR, "CHAN ERR"); +- } +- if(hcint.b.xfercomp) +- { +- // Clear the port allocation and transmit anything also on this port +- queued_port[channel] = 0; +- fiq_print(FIQDBG_SCHED, "XFERCOMP"); +- } +- if(hcint.b.nak) +- { +- queued_port[channel] = 0; +- fiq_print(FIQDBG_SCHED, "NAK"); +- } +- if(hcint.b.ack && !hcsplt.b.compsplt) +- { +- int i; +- +- // Do not complete isochronous out transactions +- if(hcchar.b.eptype == 1 && hcchar.b.epdir == 0) +- { +- queued_port[channel] = 0; +- fiq_print(FIQDBG_SCHED, "ISOC_OUT"); +- } +- else +- { +- // Make sure we check the port / hub combination that we sent this split on. +- // Do not queue a second request to the same port +- for(i = 0; i < MAX_EPS_CHANNELS; i++) +- { +- if(port_id(hcsplt) == queued_port[i]) +- { +- fiq_print(FIQDBG_ERR, "PORTERR "); +- //BUG(); +- } +- } +- +- split_start_frame[channel] = (hfnum.b.frnum + 1) & ~7; +- +- // Note, the size of an OUT is in the start split phase, not +- // the complete split +- split_out_xfersize[channel] = hctsiz.b.xfersize; +- +- hcint_saved[channel].b.chhltd = 0; +- hcint_saved[channel].b.ack = 0; +- +- queued_port[channel] = port_id(hcsplt); +- +- if(hcchar.b.eptype & 1) +- { +- // Send the periodic complete in the same oddness frame as the ACK went... +- fiq_queue_request(channel, !(hfnum.b.frnum & 1)); +- // complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1); +- } +- else +- { +- // Schedule the split complete to occur later +- complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 2); +- fiq_print(FIQDBG_SCHED, "ACK%04d%d", complete_sched[channel]/8, complete_sched[channel]%8); +- } +- } +- } +- if(hcint.b.nyet) +- { +- fiq_print(FIQDBG_ERR, "NYETERR1"); +- //BUG(); +- // Can transmit a split complete up to uframe .0 of the next frame +- if(hfnum.b.frnum <= dwc_frame_num_inc(split_start_frame[channel], 8)) +- { +- // Send it next frame +- if(hcchar.b.eptype & 1) // type 1 & 3 are interrupt & isoc +- { +- fiq_print(FIQDBG_SCHED, "NYT:SEND"); +- fiq_queue_request(channel, !(hfnum.b.frnum & 1)); +- } +- else +- { +- // Schedule non-periodic access for next frame (the odd-even bit doesn't effect NP) +- complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1); +- fiq_print(FIQDBG_SCHED, "NYT%04d%d", complete_sched[channel]/8, complete_sched[channel]%8); +- } +- hcint_saved[channel].b.chhltd = 0; +- hcint_saved[channel].b.nyet = 0; +- } +- else +- { +- queued_port[channel] = 0; +- fiq_print(FIQDBG_ERR, "NYETERR2"); +- //BUG(); +- } +- } +- } +- else +- { +- /* +- * If we have any of NAK, ACK, Datatlgerr active on a +- * non-split channel, the sole reason is to reset error +- * counts for a previously broken transaction. The FIQ +- * will thrash on NAK IN and ACK OUT in particular so +- * handle it "once" and allow the IRQ to do the rest. +- */ +- hcint.d32 &= hcintmsk.d32; +- if(hcint.b.nak) +- { +- hcintmsk.b.nak = 0; +- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); +- } +- if (hcint.b.ack) +- { +- hcintmsk.b.ack = 0; +- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); +- } +- } +- +- // Clear the interrupt, this will also clear the HAINT bit +- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32); +- return hcint_saved[channel].d32 == 0; +-} +- +-gintsts_data_t gintsts; +-gintmsk_data_t gintmsk; +-// triggered: The set of interrupts that were triggered +-// handled: The set of interrupts that have been handled (no IRQ is +-// required) +-// keep: The set of interrupts we want to keep unmasked even though we +-// want to trigger an IRQ to handle it (SOF and HCINTR) +-gintsts_data_t triggered, handled, keep; +-hfnum_data_t hfnum; +- +-void __attribute__ ((naked)) notrace dwc_otg_hcd_handle_fiq(void) +-{ +- +- /* entry takes care to store registers we will be treading on here */ +- asm __volatile__ ( +- "mov ip, sp ;" +- /* stash FIQ and normal regs */ +- "stmdb sp!, {r0-r12, lr};" +- /* !! THIS SETS THE FRAME, adjust to > sizeof locals */ +- "sub fp, ip, #512 ;" +- ); +- +- // Cannot put local variables at the beginning of the function +- // because otherwise 'C' will play with the stack pointer. any locals +- // need to be inside the following block +- do +- { +- fiq_done++; +- gintsts.d32 = FIQ_READ(dwc_regs_base + 0x14); +- gintmsk.d32 = FIQ_READ(dwc_regs_base + 0x18); +- hfnum.d32 = FIQ_READ(dwc_regs_base + 0x408); +- triggered.d32 = gintsts.d32 & gintmsk.d32; +- handled.d32 = 0; +- keep.d32 = 0; +- fiq_print(FIQDBG_INT, "FIQ "); +- fiq_print(FIQDBG_INT, "%08x", gintsts.d32); +- fiq_print(FIQDBG_INT, "%08x", gintmsk.d32); +- if(gintsts.d32) +- { +- // If port enabled +- if((FIQ_READ(dwc_regs_base + 0x440) & 0xf) == 0x5) +- { +- if(gintsts.b.sofintr) +- { +- if(fiq_sof_handle(hfnum)) +- { +- handled.b.sofintr = 1; /* Handled in FIQ */ +- } +- else +- { +- /* Keer interrupt unmasked */ +- keep.b.sofintr = 1; +- } +- { +- // Need to make sure the read and clearing of the SOF interrupt is as close as possible to avoid the possibility of missing +- // a start of frame interrupt +- gintsts_data_t gintsts = { .b.sofintr = 1 }; +- FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32); +- } +- } +- +- if(fiq_split_enable && gintsts.b.hcintr) +- { +- int i; +- haint_data_t haint; +- haintmsk_data_t haintmsk; +- +- haint.d32 = FIQ_READ(dwc_regs_base + 0x414); +- haintmsk.d32 = FIQ_READ(dwc_regs_base + 0x418); +- haint.d32 &= haintmsk.d32; +- haint_saved.d32 |= haint.d32; +- +- fiq_print(FIQDBG_INT, "hcintr"); +- fiq_print(FIQDBG_INT, "%08x", FIQ_READ(dwc_regs_base + 0x414)); +- +- // Go through each channel that has an enabled interrupt +- for(i = 0; i < 16; i++) +- if((haint.d32 >> i) & 1) +- if(fiq_hcintr_handle(i, hfnum)) +- haint_saved.d32 &= ~(1 << i); /* this was handled */ +- +- /* If we've handled all host channel interrupts then don't trigger the interrupt */ +- if(haint_saved.d32 == 0) +- { +- handled.b.hcintr = 1; +- } +- else +- { +- /* Make sure we keep the channel interrupt unmasked when triggering the IRQ */ +- keep.b.hcintr = 1; +- } +- +- { +- gintsts_data_t gintsts = { .b.hcintr = 1 }; +- +- // Always clear the channel interrupt +- FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32); +- } +- } +- } +- else +- { +- last_sof = -1; +- } +- } +- +- // Mask out the interrupts triggered - those handled - don't mask out the ones we want to keep +- gintmsk.d32 = keep.d32 | (gintmsk.d32 & ~(triggered.d32 & ~handled.d32)); +- // Save those that were triggered but not handled +- gintsts_saved.d32 |= triggered.d32 & ~handled.d32; +- FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); +- +- // Clear and save any unhandled interrupts and trigger the interrupt +- if(gintsts_saved.d32) +- { +- /* To enable the MPHI interrupt (INT 32) +- */ +- FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send); +- FIQ_WRITE( c_mphi_regs.outddb, (1 << 29)); +- +- mphi_int_count++; +- } +- } +- while(0); +- +- mb(); +- +- /* exit back to normal mode restoring everything */ +- asm __volatile__ ( +- /* return FIQ regs back to pristine state +- * and get normal regs back +- */ +- "ldmia sp!, {r0-r12, lr};" +- +- /* return */ +- "subs pc, lr, #4;" +- ); +-} +- + /** This function handles interrupts for the HCD. */ + int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) + { + int retval = 0; + static int last_time; +- + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; + gintsts_data_t gintsts; + gintmsk_data_t gintmsk; + hfnum_data_t hfnum; ++ haintmsk_data_t haintmsk; + + #ifdef DEBUG + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; +@@ -516,15 +99,29 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) + DWC_SPINLOCK(dwc_otg_hcd->lock); + /* Check if HOST Mode */ + if (dwc_otg_is_host_mode(core_if)) { +- local_fiq_disable(); +- gintmsk.d32 |= gintsts_saved.d32; +- gintsts.d32 |= gintsts_saved.d32; +- gintsts_saved.d32 = 0; +- local_fiq_enable(); ++ if (fiq_enable) { ++ local_fiq_disable(); ++ /* Pull in from the FIQ's disabled mask */ ++ gintmsk.d32 = gintmsk.d32 | ~(dwc_otg_hcd->fiq_state->gintmsk_saved.d32); ++ dwc_otg_hcd->fiq_state->gintmsk_saved.d32 = ~0; ++ } ++ ++ if (fiq_fsm_enable && ( 0x0000FFFF & ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint))) { ++ gintsts.b.hcintr = 1; ++ } ++ ++ /* Danger will robinson: fake a SOF if necessary */ ++ if (fiq_fsm_enable && (dwc_otg_hcd->fiq_state->gintmsk_saved.b.sofintr == 1)) { ++ gintsts.b.sofintr = 1; ++ } ++ gintsts.d32 &= gintmsk.d32; ++ ++ if (fiq_enable) ++ local_fiq_enable(); ++ + if (!gintsts.d32) { + goto exit_handler_routine; + } +- gintsts.d32 &= gintmsk.d32; + + #ifdef DEBUG + // We should be OK doing this because the common interrupts should already have been serviced +@@ -544,12 +141,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) + gintsts.d32, core_if); + #endif + hfnum.d32 = DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum); +- if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) +- { +- /* Note, we should never get here if the FIQ is doing it's job properly*/ +- retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); +- } +- else if (gintsts.b.sofintr) { ++ if (gintsts.b.sofintr) { + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); + } + +@@ -604,37 +196,43 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) + } + + exit_handler_routine: +- +- if (fiq_fix_enable) +- { ++ if (fiq_enable) { ++ gintmsk_data_t gintmsk_new; ++ haintmsk_data_t haintmsk_new; + local_fiq_disable(); +- // Make sure that we don't clear the interrupt if we've still got pending work to do +- if(gintsts_saved.d32 == 0) +- { +- /* Clear the MPHI interrupt */ +- DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16)); +- if (mphi_int_count >= 60) +- { +- DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16))); +- while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17))) +- ; +- DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); +- mphi_int_count = 0; +- } +- int_done++; ++ gintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->gintmsk_saved.d32; ++ if(fiq_fsm_enable) ++ haintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->haintmsk_saved.d32; ++ else ++ haintmsk_new.d32 = 0x0000FFFF; ++ ++ /* The FIQ could have sneaked another interrupt in. If so, don't clear MPHI */ ++ if ((gintmsk_new.d32 == ~0) && (haintmsk_new.d32 == 0x0000FFFF)) { ++ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.intstat, (1<<16)); ++ if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) { ++ fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR"); ++ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, ((1<<31) + (1<<16))); ++ while (!(DWC_READ_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & (1 << 17))) ++ ; ++ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, (1<<31)); ++ dwc_otg_hcd->fiq_state->mphi_int_count = 0; ++ } ++ int_done++; + } +- +- // Unmask handled interrupts +- FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); +- //DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1); +- ++ haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk); ++ /* Re-enable interrupts that the FIQ masked (first time round) */ ++ FIQ_WRITE(dwc_otg_hcd->fiq_state->dwc_regs_base + GINTMSK, gintmsk.d32); + local_fiq_enable(); + +- if((jiffies / HZ) > last_time) +- { ++ if ((jiffies / HZ) > last_time) { ++ //dwc_otg_qh_t *qh; ++ //dwc_list_link_t *cur; + /* Once a second output the fiq and irq numbers, useful for debug */ + last_time = jiffies / HZ; +- DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done); ++ // DWC_WARN("np_kick=%d AHC=%d sched_frame=%d cur_frame=%d int_done=%d fiq_done=%d", ++ // dwc_otg_hcd->fiq_state->kick_np_queues, dwc_otg_hcd->available_host_channels, ++ // dwc_otg_hcd->fiq_state->next_sched_frame, hfnum.b.frnum, int_done, dwc_otg_hcd->fiq_state->fiq_done); ++ //printk(KERN_WARNING "Periodic queues:\n"); + } + } + +@@ -686,6 +284,7 @@ static inline void track_missed_sofs(uint16_t curr_frame_number) + int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) + { + hfnum_data_t hfnum; ++ gintsts_data_t gintsts = { .d32 = 0 }; + dwc_list_link_t *qh_entry; + dwc_otg_qh_t *qh; + dwc_otg_transaction_type_e tr_type; +@@ -732,8 +331,8 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) + } + } + } +- +- g_next_sched_frame = next_sched_frame; ++ if (fiq_enable) ++ hcd->fiq_state->next_sched_frame = next_sched_frame; + + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE) { +@@ -741,10 +340,11 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) + did_something = 1; + } + +- /* Clear interrupt */ +- gintsts.b.sofintr = 1; +- DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); +- ++ /* Clear interrupt - but do not trample on the FIQ sof */ ++ if (!fiq_fsm_enable) { ++ gintsts.b.sofintr = 1; ++ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); ++ } + return 1; + } + +@@ -1020,19 +620,21 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd) + { + int i; + int retval = 0; +- haint_data_t haint; ++ haint_data_t haint = { .d32 = 0 } ; + + /* Clear appropriate bits in HCINTn to clear the interrupt bit in + * GINTSTS */ + +- haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); ++ if (!fiq_fsm_enable) ++ haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); + + // Overwrite with saved interrupts from fiq handler +- if(fiq_split_enable) ++ if(fiq_fsm_enable) + { ++ /* check the mask? */ + local_fiq_disable(); +- haint.d32 = haint_saved.d32; +- haint_saved.d32 = 0; ++ haint.b2.chint |= ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint); ++ dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint = ~0; + local_fiq_enable(); + } + +@@ -1076,9 +678,7 @@ static uint32_t get_actual_xfer_length(dwc_hc_t * hc, + *short_read = (hctsiz.b.xfersize != 0); + } + } else if (hc->qh->do_split) { +- if(fiq_split_enable) +- length = split_out_xfersize[hc->hc_num]; +- else ++ //length = split_out_xfersize[hc->hc_num]; + length = qtd->ssplit_out_xfer_count; + } else { + length = hc->xfer_len; +@@ -1325,19 +925,17 @@ static void release_channel(dwc_otg_hcd_t * hcd, + int free_qtd; + dwc_irqflags_t flags; + dwc_spinlock_t *channel_lock = hcd->channel_lock; +-#ifdef FIQ_DEBUG +- int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0; +-#endif ++ + int hog_port = 0; + + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", + __func__, hc->hc_num, halt_status, hc->xfer_len); + +- if(fiq_split_enable && hc->do_split) { ++ if(fiq_fsm_enable && hc->do_split) { + if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) { + if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID || + hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) { +- hog_port = 1; ++ hog_port = 0; + } + } + } +@@ -1394,6 +992,8 @@ static void release_channel(dwc_otg_hcd_t * hcd, + * function clears the channel interrupt enables and conditions, so + * there's no need to clear the Channel Halted interrupt separately. + */ ++ if (fiq_fsm_enable && hcd->fiq_state->channel[hc->hc_num].fsm != FIQ_PASSTHROUGH) ++ dwc_otg_cleanup_fiq_channel(hcd, hc->hc_num); + dwc_otg_hc_cleanup(hcd->core_if, hc); + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); + +@@ -1416,27 +1016,10 @@ static void release_channel(dwc_otg_hcd_t * hcd, + + DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); + hcd->available_host_channels++; +- fiq_print(FIQDBG_PORTHUB, "AHC = %d ", hcd->available_host_channels); ++ fiq_print(FIQDBG_INT, hcd->fiq_state, "AHC = %d ", hcd->available_host_channels); + DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); + } + +- if(fiq_split_enable && hc->do_split) +- { +- if(!(hcd->hub_port[hc->hub_addr] & (1 << hc->port_addr))) +- { +- fiq_print(FIQDBG_ERR, "PRTNOTAL"); +- //BUG(); +- } +- if(!hog_port && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC || +- hc->ep_type == DWC_OTG_EP_TYPE_INTR)) { +- hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); +-#ifdef FIQ_DEBUG +- hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; +-#endif +- fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); +- } +- } +- + /* Try to queue more transfers now that there's a free channel. */ + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE) { +@@ -1858,7 +1441,7 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, + switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { + case UE_BULK: + case UE_CONTROL: +- if (nak_holdoff_enable) ++ if (nak_holdoff && qtd->qh->do_split) + hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd); + } + +@@ -2074,7 +1657,7 @@ static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd, + // With the FIQ running we only ever see the failed NYET + if (dwc_full_frame_num(frnum) != + dwc_full_frame_num(hc->qh->sched_frame) || +- fiq_split_enable) { ++ fiq_fsm_enable) { + /* + * No longer in the same full speed frame. + * Treat this as a transaction error. +@@ -2460,12 +2043,11 @@ static inline int halt_status_ok(dwc_otg_hcd_t * hcd, + static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, +- dwc_otg_qtd_t * qtd, +- hcint_data_t hcint, +- hcintmsk_data_t hcintmsk) ++ dwc_otg_qtd_t * qtd) + { + int out_nak_enh = 0; +- ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; + /* For core with OUT NAK enhancement, the flow for high- + * speed CONTROL/BULK OUT is handled a little differently. + */ +@@ -2495,11 +2077,9 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + } + + /* Read the HCINTn register to determine the cause for the halt. */ +- if(!fiq_split_enable) +- { +- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); +- hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); +- } ++ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); + + if (hcint.b.xfercomp) { + /** @todo This is here because of a possible hardware bug. Spec +@@ -2624,15 +2204,13 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, +- dwc_otg_qtd_t * qtd, +- hcint_data_t hcint, +- hcintmsk_data_t hcintmsk) ++ dwc_otg_qtd_t * qtd) + { + DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " + "Channel Halted--\n", hc->hc_num); + + if (hcd->core_if->dma_enable) { +- handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd, hcint, hcintmsk); ++ handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd); + } else { + #ifdef DEBUG + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) { +@@ -2645,11 +2223,372 @@ static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, + return 1; + } + ++ ++/** ++ * dwc_otg_fiq_unmangle_isoc() - Update the iso_frame_desc structure on ++ * FIQ transfer completion ++ * @hcd: Pointer to dwc_otg_hcd struct ++ * @num: Host channel number ++ * ++ * 1. Un-mangle the status as recorded in each iso_frame_desc status ++ * 2. Copy it from the dwc_otg_urb into the real URB ++ */ ++void dwc_otg_fiq_unmangle_isoc(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num) ++{ ++ struct dwc_otg_hcd_urb *dwc_urb = qtd->urb; ++ int nr_frames = dwc_urb->packet_count; ++ int i; ++ hcint_data_t frame_hcint; ++ ++ for (i = 0; i < nr_frames; i++) { ++ frame_hcint.d32 = dwc_urb->iso_descs[i].status; ++ if (frame_hcint.b.xfercomp) { ++ dwc_urb->iso_descs[i].status = 0; ++ dwc_urb->actual_length += dwc_urb->iso_descs[i].actual_length; ++ } else if (frame_hcint.b.frmovrun) { ++ if (qh->ep_is_in) ++ dwc_urb->iso_descs[i].status = -DWC_E_NO_STREAM_RES; ++ else ++ dwc_urb->iso_descs[i].status = -DWC_E_COMMUNICATION; ++ dwc_urb->error_count++; ++ dwc_urb->iso_descs[i].actual_length = 0; ++ } else if (frame_hcint.b.xacterr) { ++ dwc_urb->iso_descs[i].status = -DWC_E_PROTOCOL; ++ dwc_urb->error_count++; ++ dwc_urb->iso_descs[i].actual_length = 0; ++ } else if (frame_hcint.b.bblerr) { ++ dwc_urb->iso_descs[i].status = -DWC_E_OVERFLOW; ++ dwc_urb->error_count++; ++ dwc_urb->iso_descs[i].actual_length = 0; ++ } else { ++ /* Something went wrong */ ++ dwc_urb->iso_descs[i].status = -1; ++ dwc_urb->iso_descs[i].actual_length = 0; ++ dwc_urb->error_count++; ++ } ++ } ++ //printk_ratelimited(KERN_INFO "%s: HS isochronous of %d/%d frames with %d errors complete\n", ++ // __FUNCTION__, i, dwc_urb->packet_count, dwc_urb->error_count); ++ hcd->fops->complete(hcd, dwc_urb->priv, dwc_urb, 0); ++ release_channel(hcd, qh->channel, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++} ++ ++/** ++ * dwc_otg_fiq_unsetup_per_dma() - Remove data from bounce buffers for split transactions ++ * @hcd: Pointer to dwc_otg_hcd struct ++ * @num: Host channel number ++ * ++ * Copies data from the FIQ bounce buffers into the URB's transfer buffer. Does not modify URB state. ++ * Returns total length of data or -1 if the buffers were not used. ++ * ++ */ ++int dwc_otg_fiq_unsetup_per_dma(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num) ++{ ++ dwc_hc_t *hc = qh->channel; ++ struct fiq_dma_blob *blob = hcd->fiq_dmab; ++ struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; ++ uint8_t *ptr = NULL; ++ int index = 0, len = 0; ++ int i = 0; ++ if (hc->ep_is_in) { ++ /* Copy data out of the DMA bounce buffers to the URB's buffer. ++ * The align_buf is ignored as this is ignored on FSM enqueue. */ ++ ptr = qtd->urb->buf; ++ if (qh->ep_type == UE_ISOCHRONOUS) { ++ /* Isoc IN transactions - grab the offset of the iso_frame_desc into the URB transfer buffer */ ++ index = qtd->isoc_frame_index; ++ ptr += qtd->urb->iso_descs[index].offset; ++ } else { ++ /* Need to increment by actual_length for interrupt IN */ ++ ptr += qtd->urb->actual_length; ++ } ++ ++ for (i = 0; i < st->dma_info.index; i++) { ++ len += st->dma_info.slot_len[i]; ++ dwc_memcpy(ptr, &blob->channel[num].index[i].buf[0], st->dma_info.slot_len[i]); ++ ptr += st->dma_info.slot_len[i]; ++ } ++ return len; ++ } else { ++ /* OUT endpoints - nothing to do. */ ++ return -1; ++ } ++ ++} ++/** ++ * dwc_otg_hcd_handle_hc_fsm() - handle an unmasked channel interrupt ++ * from a channel handled in the FIQ ++ * @hcd: Pointer to dwc_otg_hcd struct ++ * @num: Host channel number ++ * ++ * If a host channel interrupt was received by the IRQ and this was a channel ++ * used by the FIQ, the execution flow for transfer completion is substantially ++ * different from the normal (messy) path. This function and its friends handles ++ * channel cleanup and transaction completion from a FIQ transaction. ++ */ ++int32_t dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd_t *hcd, uint32_t num) ++{ ++ struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; ++ dwc_hc_t *hc = hcd->hc_ptr_array[num]; ++ dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); ++ dwc_otg_qh_t *qh = hc->qh; ++ dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[num]; ++ hcint_data_t hcint = hcd->fiq_state->channel[num].hcint_copy; ++ int hostchannels = 0; ++ int ret = 0; ++ fiq_print(FIQDBG_INT, hcd->fiq_state, "OUT %01d %01d ", num , st->fsm); ++ ++ hostchannels = hcd->available_host_channels; ++ switch (st->fsm) { ++ case FIQ_TEST: ++ break; ++ ++ case FIQ_DEQUEUE_ISSUED: ++ /* hc_halt was called. QTD no longer exists. */ ++ /* TODO: for a nonperiodic split transaction, need to issue a ++ * CLEAR_TT_BUFFER hub command if we were in the start-split phase. ++ */ ++ release_channel(hcd, hc, NULL, hc->halt_status); ++ ret = 1; ++ break; ++ ++ case FIQ_NP_SPLIT_DONE: ++ /* Nonperiodic transaction complete. */ ++ if (!hc->ep_is_in) { ++ qtd->ssplit_out_xfer_count = hc->xfer_len; ++ } ++ if (hcint.b.xfercomp) { ++ handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.nak) { ++ handle_hc_nak_intr(hcd, hc, hc_regs, qtd); ++ } ++ ret = 1; ++ break; ++ ++ case FIQ_NP_SPLIT_HS_ABORTED: ++ /* A HS abort is a 3-strikes on the HS bus at any point in the transaction. ++ * Normally a CLEAR_TT_BUFFER hub command would be required: we can't do that ++ * because there's no guarantee which order a non-periodic split happened in. ++ * We could end up clearing a perfectly good transaction out of the buffer. ++ */ ++ if (hcint.b.xacterr) { ++ qtd->error_count += st->nr_errors; ++ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.ahberr) { ++ handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); ++ } else { ++ local_fiq_disable(); ++ BUG(); ++ } ++ break; ++ ++ case FIQ_NP_SPLIT_LS_ABORTED: ++ /* A few cases can cause this - either an unknown state on a SSPLIT or ++ * STALL/data toggle error response on a CSPLIT */ ++ if (hcint.b.stall) { ++ handle_hc_stall_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.datatglerr) { ++ handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.bblerr) { ++ handle_hc_babble_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.ahberr) { ++ handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); ++ } else { ++ local_fiq_disable(); ++ BUG(); ++ } ++ break; ++ ++ case FIQ_PER_SPLIT_DONE: ++ /* Isoc IN or Interrupt IN/OUT */ ++ ++ /* Flow control here is different from the normal execution by the driver. ++ * We need to completely ignore most of the driver's method of handling ++ * split transactions and do it ourselves. ++ */ ++ if (hc->ep_type == UE_INTERRUPT) { ++ if (hcint.b.nak) { ++ handle_hc_nak_intr(hcd, hc, hc_regs, qtd); ++ } else if (hc->ep_is_in) { ++ int len; ++ len = dwc_otg_fiq_unsetup_per_dma(hcd, hc->qh, qtd, num); ++ //printk(KERN_NOTICE "FIQ Transaction: hc=%d len=%d urb_len = %d\n", num, len, qtd->urb->length); ++ qtd->urb->actual_length += len; ++ if (qtd->urb->actual_length >= qtd->urb->length) { ++ qtd->urb->status = 0; ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } else { ++ /* Interrupt transfer not complete yet - is it a short read? */ ++ if (len < hc->max_packet) { ++ /* Interrupt transaction complete */ ++ qtd->urb->status = 0; ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } else { ++ /* Further transactions required */ ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); ++ } ++ } ++ } else { ++ /* Interrupt OUT complete. */ ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ qtd->urb->actual_length += hc->xfer_len; ++ if (qtd->urb->actual_length >= qtd->urb->length) { ++ qtd->urb->status = 0; ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } else { ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); ++ } ++ } ++ } else { ++ /* ISOC IN complete. */ ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; ++ int len = 0; ++ /* Record errors, update qtd. */ ++ if (st->nr_errors) { ++ frame_desc->actual_length = 0; ++ frame_desc->status = -DWC_E_PROTOCOL; ++ } else { ++ frame_desc->status = 0; ++ /* Unswizzle dma */ ++ len = dwc_otg_fiq_unsetup_per_dma(hcd, qh, qtd, num); ++ frame_desc->actual_length = len; ++ } ++ qtd->isoc_frame_index++; ++ if (qtd->isoc_frame_index == qtd->urb->packet_count) { ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } else { ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); ++ } ++ } ++ break; ++ ++ case FIQ_PER_ISO_OUT_DONE: { ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; ++ /* Record errors, update qtd. */ ++ if (st->nr_errors) { ++ frame_desc->actual_length = 0; ++ frame_desc->status = -DWC_E_PROTOCOL; ++ } else { ++ frame_desc->status = 0; ++ frame_desc->actual_length = frame_desc->length; ++ } ++ qtd->isoc_frame_index++; ++ qtd->isoc_split_offset = 0; ++ if (qtd->isoc_frame_index == qtd->urb->packet_count) { ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } else { ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); ++ } ++ } ++ break; ++ ++ case FIQ_PER_SPLIT_NYET_ABORTED: ++ /* Doh. lost the data. */ ++ printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x frame %d failed " ++ "- FIQ reported NYET. Data may have been lost.\n", ++ hc->dev_addr, hc->ep_num, dwc_otg_hcd_get_frame_number(hcd) >> 3); ++ if (hc->ep_type == UE_ISOCHRONOUS) { ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; ++ /* Record errors, update qtd. */ ++ frame_desc->actual_length = 0; ++ frame_desc->status = -DWC_E_PROTOCOL; ++ qtd->isoc_frame_index++; ++ qtd->isoc_split_offset = 0; ++ if (qtd->isoc_frame_index == qtd->urb->packet_count) { ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } else { ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); ++ } ++ } else { ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); ++ } ++ break; ++ ++ case FIQ_HS_ISOC_DONE: ++ /* The FIQ has performed a whole pile of isochronous transactions. ++ * The status is recorded as the interrupt state should the transaction ++ * fail. ++ */ ++ dwc_otg_fiq_unmangle_isoc(hcd, qh, qtd, num); ++ break; ++ ++ case FIQ_PER_SPLIT_LS_ABORTED: ++ if (hcint.b.xacterr) { ++ /* Hub has responded with an ERR packet. Device ++ * has been unplugged or the port has been disabled. ++ * TODO: need to issue a reset to the hub port. */ ++ qtd->error_count += 3; ++ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.stall) { ++ handle_hc_stall_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.bblerr) { ++ handle_hc_babble_intr(hcd, hc, hc_regs, qtd); ++ } else { ++ printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x failed " ++ "- FIQ reported FSM=%d. Data may have been lost.\n", ++ st->fsm, hc->dev_addr, hc->ep_num); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); ++ } ++ break; ++ ++ case FIQ_PER_SPLIT_HS_ABORTED: ++ /* Either the SSPLIT phase suffered transaction errors or something ++ * unexpected happened. ++ */ ++ qtd->error_count += 3; ++ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); ++ break; ++ ++ case FIQ_PER_SPLIT_TIMEOUT: ++ /* Couldn't complete in the nominated frame */ ++ printk(KERN_INFO "Transfer to device %d endpoint 0x%x frame %d failed " ++ "- FIQ timed out. Data may have been lost.\n", ++ hc->dev_addr, hc->ep_num, dwc_otg_hcd_get_frame_number(hcd) >> 3); ++ if (hc->ep_type == UE_ISOCHRONOUS) { ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; ++ /* Record errors, update qtd. */ ++ frame_desc->actual_length = 0; ++ if (hc->ep_is_in) { ++ frame_desc->status = -DWC_E_NO_STREAM_RES; ++ } else { ++ frame_desc->status = -DWC_E_COMMUNICATION; ++ } ++ qtd->isoc_frame_index++; ++ if (qtd->isoc_frame_index == qtd->urb->packet_count) { ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } else { ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); ++ } ++ } else { ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); ++ } ++ break; ++ ++ default: ++ local_fiq_disable(); ++ DWC_WARN("unexpected state received on hc=%d fsm=%d", hc->hc_num, st->fsm); ++ BUG(); ++ } ++ //if (hostchannels != hcd->available_host_channels) { ++ /* should have incremented by now! */ ++ // BUG(); ++// } ++ return ret; ++} ++ + /** Handles interrupt for a specific Host Channel */ + int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) + { + int retval = 0; +- hcint_data_t hcint, hcint_orig; ++ hcint_data_t hcint; + hcintmsk_data_t hcintmsk; + dwc_hc_t *hc; + dwc_otg_hc_regs_t *hc_regs; +@@ -2668,24 +2607,32 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) + } + qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); + ++ /* ++ * FSM mode: Check to see if this is a HC interrupt from a channel handled by the FIQ. ++ * Execution path is fundamentally different for the channels after a FIQ has completed ++ * a split transaction. ++ */ ++ if (fiq_fsm_enable) { ++ switch (dwc_otg_hcd->fiq_state->channel[num].fsm) { ++ case FIQ_PASSTHROUGH: ++ break; ++ case FIQ_PASSTHROUGH_ERRORSTATE: ++ /* Hook into the error count */ ++ fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "HCDERR%02d", num); ++ if (dwc_otg_hcd->fiq_state->channel[num].nr_errors) { ++ qtd->error_count = 0; ++ fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "RESET "); ++ } ++ break; ++ default: ++ dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd, num); ++ return 1; ++ } ++ } ++ + hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); +- hcint_orig = hcint; + hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); +- DWC_DEBUGPL(DBG_HCDV, +- " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", +- hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); + hcint.d32 = hcint.d32 & hcintmsk.d32; +- +- if(fiq_split_enable) +- { +- // replace with the saved interrupts from the fiq handler +- local_fiq_disable(); +- hcint_orig.d32 = hcint_saved[num].d32; +- hcint.d32 = hcint_orig.d32 & hcintmsk_saved[num].d32; +- hcint_saved[num].d32 = 0; +- local_fiq_enable(); +- } +- + if (!dwc_otg_hcd->core_if->dma_enable) { + if (hcint.b.chhltd && hcint.d32 != 0x2) { + hcint.b.chhltd = 0; +@@ -2703,7 +2650,7 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) + hcint.b.nyet = 0; + } + if (hcint.b.chhltd) { +- retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd, hcint_orig, hcintmsk_saved[num]); ++ retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.ahberr) { + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd); +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +index ee8eec9..07b1808 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +@@ -58,6 +58,7 @@ + #else + #include + #endif ++#include + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) + #define USB_URB_EP_LINKING 1 +@@ -69,7 +70,8 @@ + #include "dwc_otg_dbg.h" + #include "dwc_otg_driver.h" + #include "dwc_otg_hcd.h" +-#include "dwc_otg_mphi_fix.h" ++ ++extern unsigned char _dwc_otg_fiq_stub, _dwc_otg_fiq_stub_end; + + /** + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is +@@ -80,7 +82,7 @@ + + static const char dwc_otg_hcd_name[] = "dwc_otg_hcd"; + +-extern bool fiq_fix_enable; ++extern bool fiq_enable; + + /** @name Linux HC Driver API Functions */ + /** @{ */ +@@ -351,7 +353,6 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, + urb); + } + } +- + DWC_FREE(dwc_otg_urb); + if (!new_entry) { + DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n"); +@@ -395,13 +396,9 @@ static struct dwc_otg_hcd_function_ops hcd_fops = { + static struct fiq_handler fh = { + .name = "usb_fiq", + }; +-struct fiq_stack_s { +- int magic1; +- uint8_t stack[2048]; +- int magic2; +-} fiq_stack; + +-extern mphi_regs_t c_mphi_regs; ++ ++ + /** + * Initializes the HCD. This function allocates memory for and initializes the + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the +@@ -433,20 +430,6 @@ int hcd_init(dwc_bus_dev_t *_dev) + pci_set_consistent_dma_mask(_dev, dmamask); + #endif + +- if (fiq_fix_enable) +- { +- // Set up fiq +- claim_fiq(&fh); +- set_fiq_handler(__FIQ_Branch, 4); +- memset(®s,0,sizeof(regs)); +- regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq; +- regs.ARM_r9 = (long)0; +- regs.ARM_sp = (long)fiq_stack.stack + sizeof(fiq_stack.stack) - 4; +- set_fiq_regs(®s); +- fiq_stack.magic1 = 0xdeadbeef; +- fiq_stack.magic2 = 0xaa995566; +- } +- + /* + * Allocate memory for the base HCD plus the DWC OTG HCD. + * Initialize the base HCD. +@@ -466,30 +449,7 @@ int hcd_init(dwc_bus_dev_t *_dev) + + hcd->regs = otg_dev->os_dep.base; + +- if (fiq_fix_enable) +- { +- volatile extern void *dwc_regs_base; +- +- //Set the mphi periph to the required registers +- c_mphi_regs.base = otg_dev->os_dep.mphi_base; +- c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; +- c_mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28; +- c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; +- c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; +- +- dwc_regs_base = otg_dev->os_dep.base; + +- //Enable mphi peripheral +- writel((1<<31),c_mphi_regs.ctrl); +-#ifdef DEBUG +- if (readl(c_mphi_regs.ctrl) & 0x80000000) +- DWC_DEBUGPL(DBG_USER, "MPHI periph has been enabled\n"); +- else +- DWC_DEBUGPL(DBG_USER, "MPHI periph has NOT been enabled\n"); +-#endif +- // Enable FIQ interrupt from USB peripheral +- enable_fiq(INTERRUPT_VC_USB); +- } + /* Initialize the DWC OTG HCD. */ + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd(); + if (!dwc_otg_hcd) { +@@ -503,6 +463,55 @@ int hcd_init(dwc_bus_dev_t *_dev) + goto error2; + } + ++ if (fiq_enable) ++ { ++ if (claim_fiq(&fh)) { ++ DWC_ERROR("Can't claim FIQ"); ++ goto error2; ++ } ++ ++ DWC_WARN("FIQ at 0x%08x", (fiq_fsm_enable ? (int)&dwc_otg_fiq_fsm : (int)&dwc_otg_fiq_nop)); ++ DWC_WARN("FIQ ASM at 0x%08x length %d", (int)&_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub)); ++ ++ set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub); ++ memset(®s,0,sizeof(regs)); ++ ++ regs.ARM_r8 = (long) dwc_otg_hcd->fiq_state; ++ if (fiq_fsm_enable) { ++ regs.ARM_r9 = dwc_otg_hcd->core_if->core_params->host_channels; ++ //regs.ARM_r10 = dwc_otg_hcd->dma; ++ regs.ARM_fp = (long) dwc_otg_fiq_fsm; ++ } else { ++ regs.ARM_fp = (long) dwc_otg_fiq_nop; ++ } ++ ++ regs.ARM_sp = (long) dwc_otg_hcd->fiq_stack + (sizeof(struct fiq_stack) - 4); ++ ++// __show_regs(®s); ++ set_fiq_regs(®s); ++ ++ //Set the mphi periph to the required registers ++ dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base; ++ dwc_otg_hcd->fiq_state->mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; ++ dwc_otg_hcd->fiq_state->mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28; ++ dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; ++ dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; ++ dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base; ++ DWC_WARN("MPHI regs_base at 0x%08x", (int)dwc_otg_hcd->fiq_state->mphi_regs.base); ++ //Enable mphi peripheral ++ writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl); ++#ifdef DEBUG ++ if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000) ++ DWC_WARN("MPHI periph has been enabled"); ++ else ++ DWC_WARN("MPHI periph has NOT been enabled"); ++#endif ++ // Enable FIQ interrupt from USB peripheral ++ enable_fiq(INTERRUPT_VC_USB); ++ local_fiq_enable(); ++ } ++ ++ + otg_dev->hcd->otg_dev = otg_dev; + hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel) +@@ -518,9 +527,9 @@ int hcd_init(dwc_bus_dev_t *_dev) + * IRQ line, and calls hcd_start method. + */ + #ifdef PLATFORM_INTERFACE +- retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED); ++ retval = usb_add_hcd(hcd, platform_get_irq(_dev, fiq_enable ? 0 : 1), IRQF_SHARED | IRQF_DISABLED); + #else +- retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED); ++ retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED); + #endif + if (retval < 0) { + goto error2; +@@ -617,9 +626,13 @@ void hcd_stop(struct usb_hcd *hcd) + /** Returns the current frame number. */ + static int get_frame_number(struct usb_hcd *hcd) + { ++ hprt0_data_t hprt0; + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); +- +- return dwc_otg_hcd_get_frame_number(dwc_otg_hcd); ++ hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0); ++ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) ++ return dwc_otg_hcd_get_frame_number(dwc_otg_hcd) >> 3; ++ else ++ return dwc_otg_hcd_get_frame_number(dwc_otg_hcd); + } + + #ifdef DEBUG +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c +index db95851..8706a5c 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c +@@ -41,7 +41,6 @@ + + #include "dwc_otg_hcd.h" + #include "dwc_otg_regs.h" +-#include "dwc_otg_mphi_fix.h" + + extern bool microframe_schedule; + +@@ -576,7 +575,6 @@ static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + } + + +-extern int g_next_sched_frame, g_np_count, g_np_sent; + + /** + * Schedules an interrupt or isochronous transfer in the periodic schedule. +@@ -636,9 +634,9 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry); + } + else { +- if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, g_next_sched_frame)) ++ if(fiq_enable && (DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, hcd->fiq_state->next_sched_frame))) + { +- g_next_sched_frame = qh->sched_frame; ++ hcd->fiq_state->next_sched_frame = qh->sched_frame; + + } + /* Always start in the inactive schedule. */ +@@ -679,7 +677,7 @@ int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + /* Always start in the inactive schedule. */ + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive, + &qh->qh_list_entry); +- g_np_count++; ++ //hcd->fiq_state->kick_np_queues = 1; + } else { + status = schedule_periodic(hcd, qh); + if ( !hcd->periodic_qh_count ) { +@@ -739,13 +737,12 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) + hcd->non_periodic_qh_ptr->next; + } + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); +- +- // If we've removed the last non-periodic entry then there are none left! +- g_np_count = g_np_sent; ++ //if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive)) ++ // hcd->fiq_state->kick_np_queues = 1; + } else { + deschedule_periodic(hcd, qh); + hcd->periodic_qh_count--; +- if( !hcd->periodic_qh_count ) { ++ if( !hcd->periodic_qh_count && !fiq_fsm_enable ) { + intr_mask.b.sofintr = 1; + DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, + intr_mask.d32, 0); +@@ -770,28 +767,11 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, + int sched_next_periodic_split) + { + if (dwc_qh_is_non_per(qh)) { +- +- dwc_otg_qh_t *qh_tmp; +- dwc_list_link_t *qh_list; +- DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) +- { +- qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); +- if(qh_tmp == qh) +- { +- /* +- * FIQ is being disabled because this one nevers gets a np_count increment +- * This is still not absolutely correct, but it should fix itself with +- * just an unnecessary extra interrupt +- */ +- g_np_sent = g_np_count; +- } +- } +- +- + dwc_otg_hcd_qh_remove(hcd, qh); + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { + /* Add back to inactive non-periodic schedule. */ + dwc_otg_hcd_qh_add(hcd, qh); ++ //hcd->fiq_state->kick_np_queues = 1; + } + } else { + uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd); +@@ -850,9 +830,9 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, + &qh->qh_list_entry); + } else { +- if(!dwc_frame_num_le(g_next_sched_frame, qh->sched_frame)) ++ if(fiq_enable && !dwc_frame_num_le(hcd->fiq_state->next_sched_frame, qh->sched_frame)) + { +- g_next_sched_frame = qh->sched_frame; ++ hcd->fiq_state->next_sched_frame = qh->sched_frame; + } + + DWC_LIST_MOVE_HEAD +@@ -943,6 +923,9 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, + if (*qh == NULL) { + retval = -DWC_E_NO_MEMORY; + goto done; ++ } else { ++ if (fiq_enable) ++ hcd->fiq_state->kick_np_queues = 1; + } + } + retval = dwc_otg_hcd_qh_add(hcd, *qh); +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c +deleted file mode 100755 +index 50b94a8..0000000 +--- a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c ++++ /dev/null +@@ -1,113 +0,0 @@ +-#include "dwc_otg_regs.h" +-#include "dwc_otg_dbg.h" +- +-void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name) +-{ +- DWC_DEBUGPL(DBG_USER, "*** Debugging from within the %s function: ***\n" +- "curmode: %1i Modemismatch: %1i otgintr: %1i sofintr: %1i\n" +- "rxstsqlvl: %1i nptxfempty : %1i ginnakeff: %1i goutnakeff: %1i\n" +- "ulpickint: %1i i2cintr: %1i erlysuspend:%1i usbsuspend: %1i\n" +- "usbreset: %1i enumdone: %1i isooutdrop: %1i eopframe: %1i\n" +- "restoredone: %1i epmismatch: %1i inepint: %1i outepintr: %1i\n" +- "incomplisoin:%1i incomplisoout:%1i fetsusp: %1i resetdet: %1i\n" +- "portintr: %1i hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i\n" +- "conidstschng:%1i disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", +- function_name, +- gintsts.b.curmode, +- gintsts.b.modemismatch, +- gintsts.b.otgintr, +- gintsts.b.sofintr, +- gintsts.b.rxstsqlvl, +- gintsts.b.nptxfempty, +- gintsts.b.ginnakeff, +- gintsts.b.goutnakeff, +- gintsts.b.ulpickint, +- gintsts.b.i2cintr, +- gintsts.b.erlysuspend, +- gintsts.b.usbsuspend, +- gintsts.b.usbreset, +- gintsts.b.enumdone, +- gintsts.b.isooutdrop, +- gintsts.b.eopframe, +- gintsts.b.restoredone, +- gintsts.b.epmismatch, +- gintsts.b.inepint, +- gintsts.b.outepintr, +- gintsts.b.incomplisoin, +- gintsts.b.incomplisoout, +- gintsts.b.fetsusp, +- gintsts.b.resetdet, +- gintsts.b.portintr, +- gintsts.b.hcintr, +- gintsts.b.ptxfempty, +- gintsts.b.lpmtranrcvd, +- gintsts.b.conidstschng, +- gintsts.b.disconnect, +- gintsts.b.sessreqintr, +- gintsts.b.wkupintr); +- return; +-} +- +-void dwc_debug_core_int_mask(gintmsk_data_t gintmsk, const char* function_name) +-{ +- DWC_DEBUGPL(DBG_USER, "Interrupt Mask status (called from %s) :\n" +- "modemismatch: %1i otgintr: %1i sofintr: %1i rxstsqlvl: %1i\n" +- "nptxfempty: %1i ginnakeff: %1i goutnakeff: %1i ulpickint: %1i\n" +- "i2cintr: %1i erlysuspend:%1i usbsuspend: %1i usbreset: %1i\n" +- "enumdone: %1i isooutdrop: %1i eopframe: %1i restoredone: %1i\n" +- "epmismatch: %1i inepintr: %1i outepintr: %1i incomplisoin:%1i\n" +- "incomplisoout:%1i fetsusp: %1i resetdet: %1i portintr: %1i\n" +- "hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i conidstschng:%1i\n" +- "disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", +- function_name, +- gintmsk.b.modemismatch, +- gintmsk.b.otgintr, +- gintmsk.b.sofintr, +- gintmsk.b.rxstsqlvl, +- gintmsk.b.nptxfempty, +- gintmsk.b.ginnakeff, +- gintmsk.b.goutnakeff, +- gintmsk.b.ulpickint, +- gintmsk.b.i2cintr, +- gintmsk.b.erlysuspend, +- gintmsk.b.usbsuspend, +- gintmsk.b.usbreset, +- gintmsk.b.enumdone, +- gintmsk.b.isooutdrop, +- gintmsk.b.eopframe, +- gintmsk.b.restoredone, +- gintmsk.b.epmismatch, +- gintmsk.b.inepintr, +- gintmsk.b.outepintr, +- gintmsk.b.incomplisoin, +- gintmsk.b.incomplisoout, +- gintmsk.b.fetsusp, +- gintmsk.b.resetdet, +- gintmsk.b.portintr, +- gintmsk.b.hcintr, +- gintmsk.b.ptxfempty, +- gintmsk.b.lpmtranrcvd, +- gintmsk.b.conidstschng, +- gintmsk.b.disconnect, +- gintmsk.b.sessreqintr, +- gintmsk.b.wkupintr); +- return; +-} +- +-void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name) +-{ +- DWC_DEBUGPL(DBG_USER, "otg int register (from %s function):\n" +- "sesenddet:%1i sesreqsucstschung:%2i hstnegsucstschng:%1i\n" +- "hstnegdet:%1i adevtoutchng: %2i debdone: %1i\n" +- "mvic: %1i\n", +- function_name, +- gotgint.b.sesenddet, +- gotgint.b.sesreqsucstschng, +- gotgint.b.hstnegsucstschng, +- gotgint.b.hstnegdet, +- gotgint.b.adevtoutchng, +- gotgint.b.debdone, +- gotgint.b.mvic); +- +- return; +-} +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h +deleted file mode 100755 +index ca17379..0000000 +--- a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h ++++ /dev/null +@@ -1,48 +0,0 @@ +-#ifndef __DWC_OTG_MPHI_FIX_H__ +-#define __DWC_OTG_MPHI_FIX_H__ +-#define FIQ_WRITE(_addr_,_data_) (*(volatile uint32_t *) (_addr_) = (_data_)) +-#define FIQ_READ(_addr_) (*(volatile uint32_t *) (_addr_)) +- +-typedef struct { +- volatile void* base; +- volatile void* ctrl; +- volatile void* outdda; +- volatile void* outddb; +- volatile void* intstat; +-} mphi_regs_t; +- +-void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name); +-void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name); +-void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); +- +-extern gintsts_data_t gintsts_saved; +- +-#ifdef DEBUG +-#define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__) +-#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) dwc_debug_core_int_mask(_arg_,__func__) +-#define DWC_DBG_PRINT_OTG_INT(_arg_) dwc_debug_otg_int(_arg_,__func__) +- +-#else +-#define DWC_DBG_PRINT_CORE_INT(_arg_) +-#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) +-#define DWC_DBG_PRINT_OTG_INT(_arg_) +- +-#endif +- +-typedef enum { +- FIQDBG_SCHED = (1 << 0), +- FIQDBG_INT = (1 << 1), +- FIQDBG_ERR = (1 << 2), +- FIQDBG_PORTHUB = (1 << 3), +-} FIQDBG_T; +- +-void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...); +-#ifdef FIQ_DEBUG +-#define fiq_print _fiq_print +-#else +-#define fiq_print(x, y, ...) +-#endif +- +-extern bool fiq_fix_enable, nak_holdoff_enable, fiq_split_enable; +- +-#endif +diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c +index 5d310df..4b32941 100644 +--- a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c +@@ -59,6 +59,8 @@ + #include "dwc_otg_driver.h" + #include "dwc_otg_dbg.h" + ++extern bool fiq_enable; ++ + static struct gadget_wrapper { + dwc_otg_pcd_t *pcd; + +@@ -1222,13 +1224,13 @@ int pcd_init(dwc_bus_dev_t *_dev) + */ + #ifdef PLATFORM_INTERFACE + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", +- platform_get_irq(_dev, 0)); +- retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq, ++ platform_get_irq(_dev, fiq_enable ? 0 : 1)); ++ retval = request_irq(platform_get_irq(_dev, fiq_enable ? 0 : 1), dwc_otg_pcd_irq, + IRQF_SHARED, gadget_wrapper->gadget.name, + otg_dev->pcd); + if (retval != 0) { + DWC_ERROR("request of irq%d failed\n", +- platform_get_irq(_dev, 0)); ++ platform_get_irq(_dev, fiq_enable ? 0 : 1)); + free_wrapper(gadget_wrapper); + return -EBUSY; + } -- 1.9.3 -From f9a9e7dba03b20530619d33e7253b6070514e100 Mon Sep 17 00:00:00 2001 +From 620645ee3853eae6b4f515716c5777bf55f5550d Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 055/124] bcm2835: add v4l2 camera device +Subject: [PATCH 30/53] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -97476,7 +101365,7 @@ index 0000000..c585a8f + +$ v4l2-ctl --list-formats diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index b2a4403..c1f82ec 100644 +index 20f1655..a63b88b 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -118,6 +118,7 @@ config VIDEO_S3C_CAMIF @@ -97542,7 +101431,7 @@ index 0000000..f17c79c +ccflags-$(CONFIG_VIDEO_BCM2835) += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000 diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c new file mode 100644 -index 0000000..47fe45d +index 0000000..b805c03 --- /dev/null +++ b/drivers/media/platform/bcm2835/bcm2835-camera.c @@ -0,0 +1,1478 @@ @@ -98937,7 +102826,7 @@ index 0000000..47fe45d + q->buf_struct_size = sizeof(struct mmal_buffer); + q->ops = &bm2835_mmal_video_qops; + q->mem_ops = &vb2_vmalloc_memops; -+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(q); + if (ret < 0) + goto unreg_dev; @@ -103352,10 +107241,12 @@ index 0000000..9d1d11e 1.9.3 -From 305c1692a90b7e9cc843ea7bf037ec214e492424 Mon Sep 17 00:00:00 2001 +From 6870151c2b0273977e9b932eb6afb9986f442a1e Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 10:58:01 +0000 -Subject: [PATCH 056/124] V4L2: Fix EV values. Add manual shutter speed control +Subject: [PATCH 31/53] V4L2: Fixes from 6by9 + +V4L2: Fix EV values. Add manual shutter speed control V4L2 EV values should be in units of 1/1000. Corrected. Add support for V4L2_CID_EXPOSURE_ABSOLUTE which should @@ -103363,251 +107254,428 @@ give manual shutter control. Requires manual exposure mode to be selected first. Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.h | 4 +- - drivers/media/platform/bcm2835/controls.c | 94 ++++++++++++++++++------ - drivers/media/platform/bcm2835/mmal-parameters.h | 1 + - 3 files changed, 76 insertions(+), 23 deletions(-) -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index 883eab7..5640492 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.h -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h -@@ -15,7 +15,7 @@ - * core driver device - */ - --#define V4L2_CTRL_COUNT 18 /* number of v4l controls */ -+#define V4L2_CTRL_COUNT 19 /* number of v4l controls */ - - enum { - MMAL_COMPONENT_CAMERA = 0, -@@ -51,6 +51,8 @@ struct bm2835_mmal_dev { - struct mmal_colourfx colourfx; - int hflip; - int vflip; -+ enum mmal_parameter_exposuremode exposure_mode; -+ unsigned int manual_shutter_speed; - - /* allocated mmal instance and components */ - struct vchiq_mmal_instance *instance; -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index d1408e5..481d1f6 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -30,11 +30,23 @@ - #include "mmal-parameters.h" - #include "bcm2835-camera.h" - --/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -24 to +24. -- * These are in 1/6th increments so the effective range is -4.0EV to +4.0EV. -+/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -4.0 to +4.0. -+ * MMAL values are in 1/6th increments so the MMAL range is -24 to +24. -+ * V4L2 docs say value "is expressed in terms of EV, drivers should interpret -+ * the values as 0.001 EV units, where the value 1000 stands for +1 EV." -+ * V4L2 is limited to a max of 32 values in a menu, so count in 1/3rds from -+ * -4 to +4 - */ - static const s64 ev_bias_qmenu[] = { -- -24, -21, -18, -15, -12, -9, -6, -3, 0, 3, 6, 9, 12, 15, 18, 21, 24 -+ -4000, -3667, -3333, -+ -3000, -2667, -2333, -+ -2000, -1667, -1333, -+ -1000, -667, -333, -+ 0, 333, 667, -+ 1000, 1333, 1667, -+ 2000, 2333, 2667, -+ 3000, 3333, 3667, -+ 4000 - }; - - /* Supported ISO values -@@ -166,6 +178,22 @@ static int ctrl_set_value(struct bm2835_mmal_dev *dev, - &u32_value, sizeof(u32_value)); - } - -+static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev, -+ struct v4l2_ctrl *ctrl, -+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -+{ -+ s32 s32_value; -+ struct vchiq_mmal_port *control; -+ -+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; -+ -+ s32_value = (ctrl->val-12)*2; /* Convert from index to 1/6ths */ -+ -+ return vchiq_mmal_port_parameter_set(dev->instance, control, -+ mmal_ctrl->mmal_id, -+ &s32_value, sizeof(s32_value)); -+} -+ - static int ctrl_set_rotate(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -@@ -245,34 +273,50 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) - { -- u32 u32_value; -+ enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode; -+ u32 shutter_speed = 0; - struct vchiq_mmal_port *control; -+ int ret = 0; - - control = &dev->component[MMAL_COMPONENT_CAMERA]->control; - -- switch (ctrl->val) { -- case V4L2_EXPOSURE_AUTO: -- u32_value = MMAL_PARAM_EXPOSUREMODE_AUTO; -- break; -+ if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) { -+ /* V4L2 is in 100usec increments. -+ * MMAL is 1usec. -+ */ -+ dev->manual_shutter_speed = ctrl->val * 100; -+ } else if (mmal_ctrl->mmal_id == MMAL_PARAMETER_EXPOSURE_MODE) { -+ switch (ctrl->val) { -+ case V4L2_EXPOSURE_AUTO: -+ exp_mode = MMAL_PARAM_EXPOSUREMODE_AUTO; -+ break; - -- case V4L2_EXPOSURE_MANUAL: -- u32_value = MMAL_PARAM_EXPOSUREMODE_OFF; -- break; -+ case V4L2_EXPOSURE_MANUAL: -+ exp_mode = MMAL_PARAM_EXPOSUREMODE_OFF; -+ break; - -- case V4L2_EXPOSURE_SHUTTER_PRIORITY: -- u32_value = MMAL_PARAM_EXPOSUREMODE_SPORTS; -- break; -+ case V4L2_EXPOSURE_SHUTTER_PRIORITY: -+ exp_mode = MMAL_PARAM_EXPOSUREMODE_SPORTS; -+ break; - -- case V4L2_EXPOSURE_APERTURE_PRIORITY: -- u32_value = MMAL_PARAM_EXPOSUREMODE_NIGHT; -- break; -+ case V4L2_EXPOSURE_APERTURE_PRIORITY: -+ exp_mode = MMAL_PARAM_EXPOSUREMODE_NIGHT; -+ break; - -+ } -+ dev->exposure_mode = exp_mode; - } - -- /* todo: what about the other ten modes there are MMAL parameters for */ -- return vchiq_mmal_port_parameter_set(dev->instance, control, -- mmal_ctrl->mmal_id, -- &u32_value, sizeof(u32_value)); -+ if (dev->exposure_mode == MMAL_PARAM_EXPOSUREMODE_OFF) -+ shutter_speed = dev->manual_shutter_speed; -+ -+ ret = vchiq_mmal_port_parameter_set(dev->instance, control, -+ MMAL_PARAMETER_SHUTTER_SPEED, -+ &shutter_speed, sizeof(shutter_speed)); -+ ret += vchiq_mmal_port_parameter_set(dev->instance, control, -+ MMAL_PARAMETER_EXPOSURE_MODE, -+ &exp_mode, sizeof(u32)); -+ return ret; - } - - static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev, -@@ -578,10 +622,16 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - }, - */ - { -+ V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD, -+ /* Units of 100usecs */ -+ 1, 1*1000*10, 100*10, 1, NULL, -+ MMAL_PARAMETER_SHUTTER_SPEED, &ctrl_set_exposure -+ }, -+ { - V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU, - 0, ARRAY_SIZE(ev_bias_qmenu) - 1, - (ARRAY_SIZE(ev_bias_qmenu)+1)/2 - 1, 0, ev_bias_qmenu, -- MMAL_PARAMETER_EXPOSURE_COMP, &ctrl_set_value -+ MMAL_PARAMETER_EXPOSURE_COMP, &ctrl_set_value_ev - }, - { - V4L2_CID_EXPOSURE_METERING, -diff --git a/drivers/media/platform/bcm2835/mmal-parameters.h b/drivers/media/platform/bcm2835/mmal-parameters.h -index c611b58..d8aace5 100644 ---- a/drivers/media/platform/bcm2835/mmal-parameters.h -+++ b/drivers/media/platform/bcm2835/mmal-parameters.h -@@ -161,6 +161,7 @@ enum mmal_parameter_camera_type { - MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */ - MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */ - MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_SHUTTER_SPEED /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ - }; - - enum mmal_parameter_camera_config_timestamp_mode { --- -1.9.3 - - -From 92757b5cebb9d5229e669e336e8f4a5e75da2ca7 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 9 Dec 2013 11:01:53 +0000 -Subject: [PATCH 057/124] V4L2: Correct JPEG Q-factor range +V4L2: Correct JPEG Q-factor range Should be 1-100, not 0-100 Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/controls.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index 481d1f6..c2e4c64 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -538,7 +538,7 @@ static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev, - return 0; - } - --static int ctrl_set_q_factor(struct bm2835_mmal_dev *dev, -+static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) - { -@@ -683,9 +683,9 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - }, - { - V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD, -- 0, 100, -+ 1, 100, - 30, 1, NULL, -- MMAL_PARAMETER_JPEG_Q_FACTOR, &ctrl_set_q_factor -+ MMAL_PARAMETER_JPEG_Q_FACTOR, &ctrl_set_image_encode_output - }, - }; - --- -1.9.3 - - -From 10f59634bcc7c0c72a10dab90497c6cc880a72d1 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 9 Dec 2013 11:05:24 +0000 -Subject: [PATCH 058/124] V4L2: Fix issue of driver jamming if STREAMON failed. +V4L2: Fix issue of driver jamming if STREAMON failed. Fix issue where the driver was left in a partially enabled state if STREAMON failed, and would then reject many IOCTLs as it thought it was streaming. Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) +V4L2: Fix ISO controls. + +Driver was passing the index to the GPU, and not the desired +ISO value. + +Signed-off-by: Dave Stevenson + +V4L2: Add flicker avoidance controls + +Add support for V4L2_CID_POWER_LINE_FREQUENCY to set flicker +avoidance frequencies. + +Signed-off-by: Dave Stevenson + +V4L2: Add support for frame rate control. + +Add support for frame rate (or time per frame as V4L2 +inverts it) control via s_parm. + +Signed-off-by: Dave Stevenson + +V4L2: Improve G_FBUF handling so we pass conformance + +Return some sane numbers for get framebuffer so that +we pass conformance. + +Signed-off-by: Dave Stevenson + +V4L2: Fix information advertised through g_vidfmt + +Width and height were being stored based on incorrect +values. + +Signed-off-by: Dave Stevenson + +V4L2: Add support for inline H264 headers + +Add support for V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER +to control H264 inline headers. +Requires firmware fix to work correctly, otherwise format +has to be set to H264 before this parameter is set. + +Signed-off-by: Dave Stevenson + +V4L2: Fix JPEG timestamp issue + +JPEG images were coming through from the GPU with timestamp +of 0. Detect this and give current system time instead +of some invalid value. + +Signed-off-by: Dave Stevenson + +V4L2: Fix issue when switching down JPEG resolution. + +JPEG buffer size calculation is based on input resolution. +Input resolution was being configured after output port +format. Caused failures if switching from one JPEG resolution +to a smaller one. + +Signed-off-by: Dave Stevenson + +V4L2: Enable MJPEG encoding + +Requires GPU firmware update to support MJPEG encoder. + +Signed-off-by: Dave Stevenson + +V4L2: Correct flag settings for compressed formats + +Set flags field correctly on enum_fmt_vid_cap for compressed +image formats. + +Signed-off-by: Dave Stevenson + +V4L2: H264 profile & level ctrls, FPS control and auto exp pri + +Several control handling updates. +H264 profile and level controls. +Timeperframe/FPS reworked to add V4L2_CID_EXPOSURE_AUTO_PRIORITY to +select whether AE is allowed to override the framerate specified. + +Signed-off-by: Dave Stevenson + +V4L2: Correct BGR24 to RGB24 in format table + +Signed-off-by: Dave Stevenson + +V4L2: Add additional pixel formats. Correct colourspace + +Adds the other flavours of YUYV, and NV12. +Corrects the overlay advertised colourspace. + +Signed-off-by: Dave Stevenson + +V4L2: Drop logging msg from info to debug + +Signed-off-by: Dave Stevenson + +V4L2: Initial pass at scene modes. + +Only supports exposure mode and metering modes. + +Signed-off-by: Dave Stevenson + +V4L2: Add manual white balance control. + +Adds support for V4L2_CID_RED_BALANCE and +V4L2_CID_BLUE_BALANCE. Only has an effect if +V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE has +V4L2_WHITE_BALANCE_MANUAL selected. + +Signed-off-by: Dave Stevenson + +config: Enable V4L / MMAL driver + +V4L2: Increase the MMAL timeout to 3sec + +MJPEG codec flush is now taking longer and results +in a kernel panic if the driver has stopped waiting for +the result when it finally completes. +Increase the timeout value from 1 to 3secs. + +Signed-off-by: Dave Stevenson + +V4L2: Add support for setting H264_I_PERIOD + +Adds support for the parameter V4L2_CID_MPEG_VIDEO_H264_I_PERIOD +to set the frequency with which I frames are produced. + +Signed-off-by: Dave Stevenson + +V4L2: Enable GPU function for removing padding from images. + +GPU can now support arbitrary strides, although may require +additional processing to achieve it. Enable this feature +so that the images delivered are the size requested. + +Signed-off-by: Dave Stevenson + +V4L2: Add support for V4L2_PIX_FMT_BGR32 + +Signed-off-by: Dave Stevenson + +V4L2: Set the colourspace to avoid odd YUV-RGB conversions + +Removes the amiguity from the conversion routines and stops +them dropping back to the SD vs HD choice of coeffs. + +Signed-off-by: Dave Stevenson + +V4L2: Make video/still threshold a run-time param + +Move the define for at what resolution the driver +switches from a video mode capture to a stills mode +capture to module parameters. + +Signed-off-by: Dave Stevenson + +V4L2: Fix incorrect pool sizing + +Signed-off-by: Dave Stevenson + +V4L2: Add option to disable enum_framesizes. + +Gstreamer's handling of a driver that advertises +V4L2_FRMSIZE_TYPE_STEPWISE to define the supported +resolutions is broken. See bug +https://bugzilla.gnome.org/show_bug.cgi?id=726521 + +Optional parameter of gst_v4l2src_is_broken added. +If non-zero, the driver claims not to support that +ioctl, and gstreamer should be happy again (it +guesses a set of defaults for itself). + +Signed-off-by: Dave Stevenson + +V4L2: Add support for more image formats + +Adds YVU420 (YV12), YVU420SP (NV21), and BGR888. + +Signed-off-by: Dave Stevenson + +V4L2: Extend range for V4L2_CID_MPEG_VIDEO_H264_I_PERIOD + +Request to extend the range from the fairly arbitrary +1000 frames (33 seconds at 30fps). Extend out to the +max range supported (int32 value). +Also allow 0, which is handled by the codec as only +send an I-frame on the first frame and never again. +There may be an exception if it detects a significant +scene change, but there's no easy way around that. + +Signed-off-by: Dave Stevenson +--- + arch/arm/configs/bcmrpi_defconfig | 3 + + drivers/media/platform/bcm2835/bcm2835-camera.c | 561 ++++++++++++++---- + drivers/media/platform/bcm2835/bcm2835-camera.h | 23 +- + drivers/media/platform/bcm2835/controls.c | 723 +++++++++++++++++++++-- + drivers/media/platform/bcm2835/mmal-common.h | 1 + + drivers/media/platform/bcm2835/mmal-encodings.h | 34 ++ + drivers/media/platform/bcm2835/mmal-parameters.h | 121 +++- + drivers/media/platform/bcm2835/mmal-vchiq.c | 4 +- + 8 files changed, 1292 insertions(+), 178 deletions(-) + +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index e89e430..d70da44 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -694,6 +694,9 @@ CONFIG_DVB_B2C2_FLEXCOP_USB=m + CONFIG_VIDEO_EM28XX=m + CONFIG_VIDEO_EM28XX_ALSA=m + CONFIG_VIDEO_EM28XX_DVB=m ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_BCM2835=y ++CONFIG_VIDEO_BCM2835_MMAL=m + CONFIG_RADIO_SI470X=y + CONFIG_USB_SI470X=m + CONFIG_I2C_SI470X=m diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 47fe45d..2743074 100644 +index b805c03..c0826aa 100644 --- a/drivers/media/platform/bcm2835/bcm2835-camera.c +++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -425,7 +425,15 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) +@@ -36,7 +36,8 @@ + + #define BM2835_MMAL_VERSION "0.0.2" + #define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2" +- ++#define MIN_WIDTH 16 ++#define MIN_HEIGHT 16 + #define MAX_WIDTH 2592 + #define MAX_HEIGHT 1944 + #define MIN_BUFFER_SIZE (80*1024) +@@ -53,13 +54,43 @@ int bcm2835_v4l2_debug; + module_param_named(debug, bcm2835_v4l2_debug, int, 0644); + MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2"); + ++int max_video_width = MAX_VIDEO_MODE_WIDTH; ++int max_video_height = MAX_VIDEO_MODE_HEIGHT; ++module_param(max_video_width, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(max_video_width, "Threshold for video mode"); ++module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(max_video_height, "Threshold for video mode"); ++ ++/* Gstreamer bug https://bugzilla.gnome.org/show_bug.cgi?id=726521 ++ * v4l2src does bad (and actually wrong) things when the vidioc_enum_framesizes ++ * function says type V4L2_FRMSIZE_TYPE_STEPWISE, which we do by default. ++ * It's happier if we just don't say anything at all, when it then ++ * sets up a load of defaults that it thinks might work. ++ * If gst_v4l2src_is_broken is non-zero, then we remove the function from ++ * our function table list (actually switch to an alternate set, but same ++ * result). ++ */ ++int gst_v4l2src_is_broken = 0; ++module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer"); ++ + static struct bm2835_mmal_dev *gdev; /* global device data */ + ++#define FPS_MIN 1 ++#define FPS_MAX 90 ++ ++/* timeperframe: min/max and default */ ++static const struct v4l2_fract ++ tpf_min = {.numerator = 1, .denominator = FPS_MAX}, ++ tpf_max = {.numerator = 1, .denominator = FPS_MIN}, ++ tpf_default = {.numerator = 1000, .denominator = 30000}; ++ + /* video formats */ + static struct mmal_fmt formats[] = { + { + .name = "4:2:0, packed YUV", + .fourcc = V4L2_PIX_FMT_YUV420, ++ .flags = 0, + .mmal = MMAL_ENCODING_I420, + .depth = 12, + .mmal_component = MMAL_COMPONENT_CAMERA, +@@ -67,13 +98,15 @@ static struct mmal_fmt formats[] = { + { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, ++ .flags = 0, + .mmal = MMAL_ENCODING_YUYV, + .depth = 16, + .mmal_component = MMAL_COMPONENT_CAMERA, + }, + { +- .name = "RGB24 (BE)", +- .fourcc = V4L2_PIX_FMT_BGR24, ++ .name = "RGB24 (LE)", ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .flags = 0, + .mmal = MMAL_ENCODING_BGR24, + .depth = 24, + .mmal_component = MMAL_COMPONENT_CAMERA, +@@ -81,6 +114,7 @@ static struct mmal_fmt formats[] = { + { + .name = "JPEG", + .fourcc = V4L2_PIX_FMT_JPEG, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal = MMAL_ENCODING_JPEG, + .depth = 8, + .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE, +@@ -88,10 +122,83 @@ static struct mmal_fmt formats[] = { + { + .name = "H264", + .fourcc = V4L2_PIX_FMT_H264, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal = MMAL_ENCODING_H264, + .depth = 8, + .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, +- } ++ }, ++ { ++ .name = "MJPEG", ++ .fourcc = V4L2_PIX_FMT_MJPEG, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, ++ .mmal = MMAL_ENCODING_MJPEG, ++ .depth = 8, ++ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, ++ }, ++ { ++ .name = "4:2:2, packed, YVYU", ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .flags = 0, ++ .mmal = MMAL_ENCODING_YVYU, ++ .depth = 16, ++ .mmal_component = MMAL_COMPONENT_CAMERA, ++ }, ++ { ++ .name = "4:2:2, packed, VYUY", ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .flags = 0, ++ .mmal = MMAL_ENCODING_VYUY, ++ .depth = 16, ++ .mmal_component = MMAL_COMPONENT_CAMERA, ++ }, ++ { ++ .name = "4:2:2, packed, UYVY", ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .flags = 0, ++ .mmal = MMAL_ENCODING_UYVY, ++ .depth = 16, ++ .mmal_component = MMAL_COMPONENT_CAMERA, ++ }, ++ { ++ .name = "4:2:0, packed, NV12", ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .flags = 0, ++ .mmal = MMAL_ENCODING_NV12, ++ .depth = 12, ++ .mmal_component = MMAL_COMPONENT_CAMERA, ++ }, ++ { ++ .name = "RGB24 (BE)", ++ .fourcc = V4L2_PIX_FMT_BGR24, ++ .flags = 0, ++ .mmal = MMAL_ENCODING_RGB24, ++ .depth = 24, ++ .mmal_component = MMAL_COMPONENT_CAMERA, ++ }, ++ { ++ .name = "4:2:0, packed YVU", ++ .fourcc = V4L2_PIX_FMT_YVU420, ++ .flags = 0, ++ .mmal = MMAL_ENCODING_YV12, ++ .depth = 12, ++ .mmal_component = MMAL_COMPONENT_CAMERA, ++ }, ++ { ++ .name = "4:2:0, packed, NV21", ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .flags = 0, ++ .mmal = MMAL_ENCODING_NV21, ++ .depth = 12, ++ .mmal_component = MMAL_COMPONENT_CAMERA, ++ }, ++ { ++ .name = "RGB32 (BE)", ++ .fourcc = V4L2_PIX_FMT_BGR32, ++ .flags = 0, ++ .mmal = MMAL_ENCODING_BGRA, ++ .depth = 32, ++ .mmal_component = MMAL_COMPONENT_CAMERA, ++ }, + }; + + static struct mmal_fmt *get_format(struct v4l2_format *f) +@@ -229,7 +336,8 @@ static void buffer_cb(struct vchiq_mmal_instance *instance, + } + } else { + if (dev->capture.frame_count) { +- if (dev->capture.vc_start_timestamp != -1) { ++ if (dev->capture.vc_start_timestamp != -1 && ++ pts != 0) { + s64 runtime_us = pts - + dev->capture.vc_start_timestamp; + u32 div = 0; +@@ -250,7 +358,7 @@ static void buffer_cb(struct vchiq_mmal_instance *instance, + USEC_PER_SEC; + } + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, +- "Convert start time %d.%06d and %llu" ++ "Convert start time %d.%06d and %llu " + "with offset %llu to %d.%06d\n", + (int)dev->capture.kernel_start_ts. + tv_sec, +@@ -425,7 +533,15 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb); if (ret) { v4l2_err(&dev->v4l2_dev, @@ -103624,444 +107692,15 @@ index 47fe45d..2743074 100644 return -1; } --- -1.9.3 - - -From f98085008c2cd1027146ee6fc63da049e73de6b7 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 9 Dec 2013 15:30:48 +0000 -Subject: [PATCH 059/124] V4L2: Fix ISO controls. - -Driver was passing the index to the GPU, and not the desired -ISO value. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/controls.c | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index c2e4c64..92863f7 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -178,6 +178,25 @@ static int ctrl_set_value(struct bm2835_mmal_dev *dev, - &u32_value, sizeof(u32_value)); +@@ -530,6 +646,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, + + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; ++ f->flags = fmt->flags; + + return 0; } - -+static int ctrl_set_value_menu(struct bm2835_mmal_dev *dev, -+ struct v4l2_ctrl *ctrl, -+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -+{ -+ u32 u32_value; -+ struct vchiq_mmal_port *control; -+ -+ if (ctrl->val > mmal_ctrl->max || ctrl->val < mmal_ctrl->min) -+ return 1; -+ -+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; -+ -+ u32_value = mmal_ctrl->imenu[ctrl->val]; -+ -+ return vchiq_mmal_port_parameter_set(dev->instance, control, -+ mmal_ctrl->mmal_id, -+ &u32_value, sizeof(u32_value)); -+} -+ - static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -@@ -601,7 +620,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - { - V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU, - 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu, -- MMAL_PARAMETER_ISO, &ctrl_set_value -+ MMAL_PARAMETER_ISO, &ctrl_set_value_menu - }, - { - V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD, --- -1.9.3 - - -From fb1a49ad51ee48ca00c3c1fa5b6f6ccb9d4f8d47 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 9 Dec 2013 16:40:24 +0000 -Subject: [PATCH 060/124] V4L2: Add flicker avoidance controls - -Add support for V4L2_CID_POWER_LINE_FREQUENCY to set flicker -avoidance frequencies. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.h | 2 +- - drivers/media/platform/bcm2835/controls.c | 42 ++++++++++++++++++++++++ - drivers/media/platform/bcm2835/mmal-parameters.h | 8 +++++ - 3 files changed, 51 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index 5640492..a53c3bd 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.h -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h -@@ -15,7 +15,7 @@ - * core driver device - */ - --#define V4L2_CTRL_COUNT 19 /* number of v4l controls */ -+#define V4L2_CTRL_COUNT 20 /* number of v4l controls */ - - enum { - MMAL_COMPONENT_CAMERA = 0, -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index 92863f7..7cc97c8 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -56,6 +56,13 @@ static const s64 iso_qmenu[] = { - 0, 100, 200, 400, 800, - }; - -+static const s64 mains_freq_qmenu[] = { -+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, -+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ, -+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, -+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO -+}; -+ - /* Supported video encode modes */ - static const s64 bitrate_mode_qmenu[] = { - (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, -@@ -373,6 +380,35 @@ static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev, - &u32_value, sizeof(u32_value)); - } - -+static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev, -+ struct v4l2_ctrl *ctrl, -+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -+{ -+ u32 u32_value; -+ struct vchiq_mmal_port *control; -+ -+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; -+ -+ switch (ctrl->val) { -+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: -+ u32_value = MMAL_PARAM_FLICKERAVOID_OFF; -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: -+ u32_value = MMAL_PARAM_FLICKERAVOID_50HZ; -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: -+ u32_value = MMAL_PARAM_FLICKERAVOID_60HZ; -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: -+ u32_value = MMAL_PARAM_FLICKERAVOID_AUTO; -+ break; -+ } -+ -+ return vchiq_mmal_port_parameter_set(dev->instance, control, -+ mmal_ctrl->mmal_id, -+ &u32_value, sizeof(u32_value)); -+} -+ - static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -@@ -706,6 +742,12 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - 30, 1, NULL, - MMAL_PARAMETER_JPEG_Q_FACTOR, &ctrl_set_image_encode_output - }, -+ { -+ V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU, -+ 0, ARRAY_SIZE(mains_freq_qmenu) - 1, -+ 1, 1, NULL, -+ MMAL_PARAMETER_FLICKER_AVOID, &ctrl_set_flicker_avoidance -+ }, - }; - - int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev) -diff --git a/drivers/media/platform/bcm2835/mmal-parameters.h b/drivers/media/platform/bcm2835/mmal-parameters.h -index d8aace5..b3d2c39 100644 ---- a/drivers/media/platform/bcm2835/mmal-parameters.h -+++ b/drivers/media/platform/bcm2835/mmal-parameters.h -@@ -271,6 +271,14 @@ enum mmal_parameter_imagefx { - MMAL_PARAM_IMAGEFX_CARTOON, - }; - -+enum MMAL_PARAM_FLICKERAVOID_T { -+ MMAL_PARAM_FLICKERAVOID_OFF, -+ MMAL_PARAM_FLICKERAVOID_AUTO, -+ MMAL_PARAM_FLICKERAVOID_50HZ, -+ MMAL_PARAM_FLICKERAVOID_60HZ, -+ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF -+}; -+ - /** Manner of video rate control */ - enum mmal_parameter_rate_control_mode { - MMAL_VIDEO_RATECONTROL_DEFAULT, --- -1.9.3 - - -From fa4a4dc6fff471aa10e7e8e1624450ac6d2b6231 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 13 Dec 2013 15:54:13 +0000 -Subject: [PATCH 061/124] V4L2: Add support for frame rate control. - -Add support for frame rate (or time per frame as V4L2 -inverts it) control via s_parm. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 115 +++++++++++++++++++++-- - drivers/media/platform/bcm2835/bcm2835-camera.h | 4 +- - drivers/media/platform/bcm2835/controls.c | 5 +- - drivers/media/platform/bcm2835/mmal-parameters.h | 5 + - 4 files changed, 116 insertions(+), 13 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 2743074..8c38d03 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -55,6 +55,15 @@ MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2"); - - static struct bm2835_mmal_dev *gdev; /* global device data */ - -+#define FPS_MIN 1 -+#define FPS_MAX 30 -+ -+/* timeperframe: min/max and default */ -+static const struct v4l2_fract -+ tpf_min = {.numerator = 1, .denominator = FPS_MAX}, -+ tpf_max = {.numerator = 1, .denominator = FPS_MIN}, -+ tpf_default = {.numerator = 1000, .denominator = 30000}; -+ - /* video formats */ - static struct mmal_fmt formats[] = { - { -@@ -869,8 +878,10 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - camera_port->es.video.crop.y = 0; - camera_port->es.video.crop.width = f->fmt.pix.width; - camera_port->es.video.crop.height = f->fmt.pix.height; -- camera_port->es.video.frame_rate.num = 30; -- camera_port->es.video.frame_rate.den = 1; -+ camera_port->es.video.frame_rate.num = -+ dev->capture.timeperframe.denominator; -+ camera_port->es.video.frame_rate.den = -+ dev->capture.timeperframe.numerator; - - ret = vchiq_mmal_port_set_format(dev->instance, camera_port); - -@@ -1064,6 +1075,90 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - return ret; - } - -+/* timeperframe is arbitrary and continous */ -+static int vidioc_enum_frameintervals(struct file *file, void *priv, -+ struct v4l2_frmivalenum *fival) -+{ -+ if (fival->index) -+ return -EINVAL; -+ -+ /* regarding width & height - we support any */ -+ -+ fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; -+ -+ /* fill in stepwise (step=1.0 is requred by V4L2 spec) */ -+ fival->stepwise.min = tpf_min; -+ fival->stepwise.max = tpf_max; -+ fival->stepwise.step = (struct v4l2_fract) {1, 1}; -+ -+ return 0; -+} -+ -+static int vidioc_g_parm(struct file *file, void *priv, -+ struct v4l2_streamparm *parm) -+{ -+ struct bm2835_mmal_dev *dev = video_drvdata(file); -+ -+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ -+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; -+ parm->parm.capture.timeperframe = dev->capture.timeperframe; -+ parm->parm.capture.readbuffers = 1; -+ return 0; -+} -+ -+#define FRACT_CMP(a, OP, b) \ -+ ((u64)(a).numerator * (b).denominator OP \ -+ (u64)(b).numerator * (a).denominator) -+ -+static int vidioc_s_parm(struct file *file, void *priv, -+ struct v4l2_streamparm *parm) -+{ -+ struct bm2835_mmal_dev *dev = video_drvdata(file); -+ struct v4l2_fract tpf; -+ struct mmal_parameter_rational fps_param; -+ int ret; -+ -+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ -+ tpf = parm->parm.capture.timeperframe; -+ -+ /* tpf: {*, 0} resets timing; clip to [min, max]*/ -+ tpf = tpf.denominator ? tpf : tpf_default; -+ tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf; -+ tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf; -+ -+ dev->capture.timeperframe = tpf; -+ parm->parm.capture.timeperframe = tpf; -+ parm->parm.capture.readbuffers = 1; -+ -+ fps_param.num = dev->capture.timeperframe.denominator; -+ fps_param.den = dev->capture.timeperframe.numerator; -+ ret = vchiq_mmal_port_parameter_set(dev->instance, -+ &dev->component[MMAL_COMPONENT_CAMERA]-> -+ output[MMAL_CAMERA_PORT_PREVIEW], -+ MMAL_PARAMETER_VIDEO_FRAME_RATE, -+ &fps_param, sizeof(fps_param)); -+ ret += vchiq_mmal_port_parameter_set(dev->instance, -+ &dev->component[MMAL_COMPONENT_CAMERA]-> -+ output[MMAL_CAMERA_PORT_VIDEO], -+ MMAL_PARAMETER_VIDEO_FRAME_RATE, -+ &fps_param, sizeof(fps_param)); -+ ret += vchiq_mmal_port_parameter_set(dev->instance, -+ &dev->component[MMAL_COMPONENT_CAMERA]-> -+ output[MMAL_CAMERA_PORT_CAPTURE], -+ MMAL_PARAMETER_VIDEO_FRAME_RATE, -+ &fps_param, sizeof(fps_param)); -+ if (ret) -+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev, -+ "Failed to set fps ret %d\n", -+ ret); -+ -+ return 0; -+} -+ - static const struct v4l2_ioctl_ops camera0_ioctl_ops = { - /* overlay */ - .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, -@@ -1092,6 +1187,9 @@ static const struct v4l2_ioctl_ops camera0_ioctl_ops = { - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, -+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals, -+ .vidioc_g_parm = vidioc_g_parm, -+ .vidioc_s_parm = vidioc_s_parm, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - -@@ -1184,8 +1282,10 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) - format->es->video.crop.y = 0; - format->es->video.crop.width = 1024; - format->es->video.crop.height = 768; -- format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; -- format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; -+ format->es->video.frame_rate.num = -+ dev->capture.timeperframe.denominator; -+ format->es->video.frame_rate.den = -+ dev->capture.timeperframe.numerator; - - format = - &dev->component[MMAL_COMPONENT_CAMERA]-> -@@ -1200,8 +1300,10 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) - format->es->video.crop.y = 0; - format->es->video.crop.width = 1024; - format->es->video.crop.height = 768; -- format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; -- format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; -+ format->es->video.frame_rate.num = -+ dev->capture.timeperframe.denominator; -+ format->es->video.frame_rate.den = -+ dev->capture.timeperframe.numerator; - - format = - &dev->component[MMAL_COMPONENT_CAMERA]-> -@@ -1222,6 +1324,7 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) - dev->capture.height = format->es->video.height; - dev->capture.fmt = &formats[0]; - dev->capture.encode_component = NULL; -+ dev->capture.timeperframe = tpf_default; - - /* get the preview component ready */ - ret = vchiq_mmal_component_init( -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index a53c3bd..0f29b1a 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.h -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h -@@ -32,9 +32,6 @@ enum { - MMAL_CAMERA_PORT_COUNT - }; - --#define PREVIEW_FRAME_RATE_NUM 30 --#define PREVIEW_FRAME_RATE_DEN 1 -- - #define PREVIEW_LAYER 2 - - extern int bcm2835_v4l2_debug; -@@ -66,6 +63,7 @@ struct bm2835_mmal_dev { - unsigned int height; /* height */ - unsigned int stride; /* stride */ - struct mmal_fmt *fmt; -+ struct v4l2_fract timeperframe; - - /* H264 encode bitrate */ - int encode_bitrate; -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index 7cc97c8..e965ca3 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -152,10 +152,7 @@ static int ctrl_set_rational(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) - { -- struct { -- s32 num; /**< Numerator */ -- s32 den; /**< Denominator */ -- } rational_value; -+ struct mmal_parameter_rational rational_value; - struct vchiq_mmal_port *control; - - control = &dev->component[MMAL_COMPONENT_CAMERA]->control; -diff --git a/drivers/media/platform/bcm2835/mmal-parameters.h b/drivers/media/platform/bcm2835/mmal-parameters.h -index b3d2c39..0f2bd50 100644 ---- a/drivers/media/platform/bcm2835/mmal-parameters.h -+++ b/drivers/media/platform/bcm2835/mmal-parameters.h -@@ -164,6 +164,11 @@ enum mmal_parameter_camera_type { - MMAL_PARAMETER_SHUTTER_SPEED /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ - }; - -+struct mmal_parameter_rational { -+ s32 num; /**< Numerator */ -+ s32 den; /**< Denominator */ -+}; -+ - enum mmal_parameter_camera_config_timestamp_mode { - MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */ - MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value --- -1.9.3 - - -From 262d889739356b4705fb90ebe99c0cabbeb9f37e Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 9 Dec 2013 17:30:09 +0000 -Subject: [PATCH 062/124] V4L2: Improve G_FBUF handling so we pass conformance - -Return some sane numbers for get framebuffer so that -we pass conformance. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 8c38d03..c8d8742 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -664,10 +664,18 @@ static int vidioc_g_fbuf(struct file *file, void *fh, +@@ -647,10 +764,18 @@ static int vidioc_g_fbuf(struct file *file, void *fh, { /* The video overlay must stay within the framebuffer and can't be positioned independently. */ @@ -104079,426 +107718,138 @@ index 8c38d03..c8d8742 100644 + a->fmt.bytesperline = (preview_port->es.video.width * 3)>>1; + a->fmt.sizeimage = (preview_port->es.video.width * + preview_port->es.video.height * 3)>>1; -+ a->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; ++ a->fmt.colorspace = V4L2_COLORSPACE_JPEG; return 0; } --- -1.9.3 - - -From 0bffbd9f92152b2528dcef65e0a7c6ad3455101d Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 9 Dec 2013 17:29:39 +0000 -Subject: [PATCH 063/124] V4L2: Fix information advertised through g_vidfmt - -Width and height were being stored based on incorrect -values. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index c8d8742..4766a9c 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -1028,13 +1028,19 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - if (!ret) { - dev->capture.fmt = mfmt; - dev->capture.stride = f->fmt.pix.bytesperline; -- dev->capture.width = port->es.video.crop.width; -- dev->capture.height = port->es.video.crop.height; -+ dev->capture.width = camera_port->es.video.crop.width; -+ dev->capture.height = camera_port->es.video.crop.height; +@@ -717,6 +842,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - /* select port for capture */ - dev->capture.port = port; - dev->capture.camera_port = camera_port; - dev->capture.encode_component = encode_component; -+ v4l2_dbg(1, bcm2835_v4l2_debug, -+ &dev->v4l2_dev, -+ "Set dev->capture.fmt %08X, %dx%d, stride %d", -+ port->format.encoding, -+ dev->capture.width, dev->capture.height, -+ dev->capture.stride); - } - } - --- -1.9.3 - - -From e170104529ccb4da51ceb9421adbb4ced6fbef57 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 9 Dec 2013 11:03:54 +0000 -Subject: [PATCH 064/124] V4L2: Add support for inline H264 headers - -Add support for V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER -to control H264 inline headers. -Requires firmware fix to work correctly, otherwise format -has to be set to H264 before this parameter is set. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.h | 2 +- - drivers/media/platform/bcm2835/controls.c | 115 ++++++++++++++++++----- - drivers/media/platform/bcm2835/mmal-parameters.h | 11 ++- - 3 files changed, 103 insertions(+), 25 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index 0f29b1a..25aa91f 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.h -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h -@@ -15,7 +15,7 @@ - * core driver device - */ - --#define V4L2_CTRL_COUNT 20 /* number of v4l controls */ -+#define V4L2_CTRL_COUNT 21 /* number of v4l controls */ - - enum { - MMAL_COMPONENT_CAMERA = 0, -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index e965ca3..cb062a9 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -96,6 +96,7 @@ struct bm2835_mmal_v4l2_ctrl { - const s64 *imenu; /* integer menu array */ - u32 mmal_id; /* mmal parameter id */ - bm2835_mmal_v4l2_ctrl_cb *setter; -+ bool ignore_errors; - }; - - struct v4l2_to_mmal_effects_setting { -@@ -606,12 +607,29 @@ static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev, - &u32_value, sizeof(u32_value)); + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; ++ f->flags = fmt->flags; ++ + return 0; } -+static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev, -+ struct v4l2_ctrl *ctrl, -+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -+{ -+ u32 u32_value; -+ struct vchiq_mmal_port *vid_enc_ctl; -+ -+ vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0]; -+ -+ u32_value = ctrl->val; -+ -+ return vchiq_mmal_port_parameter_set(dev->instance, vid_enc_ctl, -+ mmal_ctrl->mmal_id, -+ &u32_value, sizeof(u32_value)); -+} -+ - static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl) - { - struct bm2835_mmal_dev *dev = - container_of(ctrl->handler, struct bm2835_mmal_dev, - ctrl_handler); - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl = ctrl->priv; -+ int ret; +@@ -729,20 +856,13 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + f->fmt.pix.height = dev->capture.height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = dev->capture.fmt->fourcc; +- f->fmt.pix.bytesperline = +- (f->fmt.pix.width * dev->capture.fmt->depth) >> 3; +- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; +- if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG +- && f->fmt.pix.sizeimage < (100 << 10)) { +- /* Need a minimum size for JPEG to account for EXIF. */ +- f->fmt.pix.sizeimage = (100 << 10); +- } ++ f->fmt.pix.bytesperline = dev->capture.stride; ++ f->fmt.pix.sizeimage = dev->capture.buffersize; - if ((mmal_ctrl == NULL) || - (mmal_ctrl->id != ctrl->id) || -@@ -620,7 +638,10 @@ static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl) - return -EINVAL; +- if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_YUYV || +- dev->capture.fmt->fourcc == V4L2_PIX_FMT_UYVY) +- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; +- else ++ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24) + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; ++ else ++ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + f->fmt.pix.priv = 0; + + v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix, +@@ -766,21 +886,35 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } -- return mmal_ctrl->setter(dev, ctrl, mmal_ctrl); -+ ret = mmal_ctrl->setter(dev, ctrl, mmal_ctrl); -+ if (mmal_ctrl->ignore_errors) -+ ret = 0; -+ return ret; - } - - static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = { -@@ -633,32 +654,44 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - { - V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD, - -100, 100, 0, 1, NULL, -- MMAL_PARAMETER_SATURATION, &ctrl_set_rational -+ MMAL_PARAMETER_SATURATION, -+ &ctrl_set_rational, -+ false - }, - { - V4L2_CID_SHARPNESS, MMAL_CONTROL_TYPE_STD, - -100, 100, 0, 1, NULL, -- MMAL_PARAMETER_SHARPNESS, &ctrl_set_rational -+ MMAL_PARAMETER_SHARPNESS, -+ &ctrl_set_rational, -+ false - }, - { - V4L2_CID_CONTRAST, MMAL_CONTROL_TYPE_STD, - -100, 100, 0, 1, NULL, -- MMAL_PARAMETER_CONTRAST, &ctrl_set_rational -+ MMAL_PARAMETER_CONTRAST, -+ &ctrl_set_rational, -+ false - }, - { - V4L2_CID_BRIGHTNESS, MMAL_CONTROL_TYPE_STD, - 0, 100, 50, 1, NULL, -- MMAL_PARAMETER_BRIGHTNESS, &ctrl_set_rational -+ MMAL_PARAMETER_BRIGHTNESS, -+ &ctrl_set_rational, -+ false - }, - { - V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU, - 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu, -- MMAL_PARAMETER_ISO, &ctrl_set_value_menu -+ MMAL_PARAMETER_ISO, -+ &ctrl_set_value_menu, -+ false - }, - { - V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD, - 0, 1, 0, 1, NULL, -- MMAL_PARAMETER_VIDEO_STABILISATION, &ctrl_set_value -+ MMAL_PARAMETER_VIDEO_STABILISATION, -+ &ctrl_set_value, -+ false - }, - /* { - 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL -@@ -666,7 +699,9 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - */ { - V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU, - ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL, -- MMAL_PARAMETER_EXPOSURE_MODE, &ctrl_set_exposure -+ MMAL_PARAMETER_EXPOSURE_MODE, -+ &ctrl_set_exposure, -+ false - }, - /* todo this needs mixing in with set exposure - { -@@ -677,86 +712,120 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD, - /* Units of 100usecs */ - 1, 1*1000*10, 100*10, 1, NULL, -- MMAL_PARAMETER_SHUTTER_SPEED, &ctrl_set_exposure -+ MMAL_PARAMETER_SHUTTER_SPEED, -+ &ctrl_set_exposure, -+ false - }, - { - V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU, - 0, ARRAY_SIZE(ev_bias_qmenu) - 1, - (ARRAY_SIZE(ev_bias_qmenu)+1)/2 - 1, 0, ev_bias_qmenu, -- MMAL_PARAMETER_EXPOSURE_COMP, &ctrl_set_value_ev -+ MMAL_PARAMETER_EXPOSURE_COMP, -+ &ctrl_set_value_ev, -+ false - }, - { - V4L2_CID_EXPOSURE_METERING, - MMAL_CONTROL_TYPE_STD_MENU, - ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL, -- MMAL_PARAMETER_EXP_METERING_MODE, &ctrl_set_metering_mode -+ MMAL_PARAMETER_EXP_METERING_MODE, -+ &ctrl_set_metering_mode, -+ false - }, - { - V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, - MMAL_CONTROL_TYPE_STD_MENU, - ~0x3fe, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL, -- MMAL_PARAMETER_AWB_MODE, &ctrl_set_awb_mode -+ MMAL_PARAMETER_AWB_MODE, -+ &ctrl_set_awb_mode, -+ false - }, - { - V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU, - 0, 15, V4L2_COLORFX_NONE, 0, NULL, -- MMAL_PARAMETER_IMAGE_EFFECT, &ctrl_set_image_effect -+ MMAL_PARAMETER_IMAGE_EFFECT, -+ &ctrl_set_image_effect, -+ false - }, - { - V4L2_CID_COLORFX_CBCR, MMAL_CONTROL_TYPE_STD, - 0, 0xffff, 0x8080, 1, NULL, -- MMAL_PARAMETER_COLOUR_EFFECT, &ctrl_set_colfx -+ MMAL_PARAMETER_COLOUR_EFFECT, -+ &ctrl_set_colfx, -+ false - }, - { - V4L2_CID_ROTATE, MMAL_CONTROL_TYPE_STD, - 0, 360, 0, 90, NULL, -- MMAL_PARAMETER_ROTATION, &ctrl_set_rotate -+ MMAL_PARAMETER_ROTATION, -+ &ctrl_set_rotate, -+ false - }, - { - V4L2_CID_HFLIP, MMAL_CONTROL_TYPE_STD, - 0, 1, 0, 1, NULL, -- MMAL_PARAMETER_MIRROR, &ctrl_set_flip -+ MMAL_PARAMETER_MIRROR, -+ &ctrl_set_flip, -+ false - }, - { - V4L2_CID_VFLIP, MMAL_CONTROL_TYPE_STD, - 0, 1, 0, 1, NULL, -- MMAL_PARAMETER_MIRROR, &ctrl_set_flip -+ MMAL_PARAMETER_MIRROR, -+ &ctrl_set_flip, -+ false - }, - { - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU, - 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1, - 0, 0, bitrate_mode_qmenu, -- MMAL_PARAMETER_RATECONTROL, &ctrl_set_bitrate_mode -+ MMAL_PARAMETER_RATECONTROL, -+ &ctrl_set_bitrate_mode, -+ false - }, - { - V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD, - 25*1000, 25*1000*1000, 10*1000*1000, 25*1000, NULL, -- MMAL_PARAMETER_VIDEO_BIT_RATE, &ctrl_set_bitrate -+ MMAL_PARAMETER_VIDEO_BIT_RATE, -+ &ctrl_set_bitrate, -+ false - }, - { - V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD, - 1, 100, - 30, 1, NULL, -- MMAL_PARAMETER_JPEG_Q_FACTOR, &ctrl_set_image_encode_output -+ MMAL_PARAMETER_JPEG_Q_FACTOR, -+ &ctrl_set_image_encode_output, -+ false - }, - { - V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU, - 0, ARRAY_SIZE(mains_freq_qmenu) - 1, - 1, 1, NULL, -- MMAL_PARAMETER_FLICKER_AVOID, &ctrl_set_flicker_avoidance -+ MMAL_PARAMETER_FLICKER_AVOID, -+ &ctrl_set_flicker_avoidance, -+ false -+ }, -+ { -+ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, MMAL_CONTROL_TYPE_STD, -+ 0, 1, -+ 0, 1, NULL, -+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, -+ &ctrl_set_video_encode_param_output, -+ true /* Errors ignored as requires latest firmware to work */ - }, - }; - - int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev) - { - int c; -- int ret; -+ int ret = 0; - - for (c = 0; c < V4L2_CTRL_COUNT; c++) { - if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) { - ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c], - &v4l2_ctrls[c]); -- if (ret) -+ if (!v4l2_ctrls[c]. ignore_errors && ret) - break; - } - } -diff --git a/drivers/media/platform/bcm2835/mmal-parameters.h b/drivers/media/platform/bcm2835/mmal-parameters.h -index 0f2bd50..b08a4b0 100644 ---- a/drivers/media/platform/bcm2835/mmal-parameters.h -+++ b/drivers/media/platform/bcm2835/mmal-parameters.h -@@ -421,7 +421,16 @@ enum mmal_parameter_video_type { - MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER, - - /** @ref MMAL_PARAMETER_BYTES_T */ -- MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3 -+ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3, + f->fmt.pix.field = V4L2_FIELD_NONE; +- /* image must be a multiple of 32 pixels wide and 16 lines high */ +- v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 5, +- &f->fmt.pix.height, 32, MAX_HEIGHT, 4, 0); +- f->fmt.pix.bytesperline = (f->fmt.pix.width * mfmt->depth) >> 3; +- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; +- if (f->fmt.pix.sizeimage < MIN_BUFFER_SIZE) + -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS, ++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, ++ "Clipping/aligning %dx%d format %08X\n", ++ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); + -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, ++ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 1, ++ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 1, 0); ++ f->fmt.pix.bytesperline = (f->fmt.pix.width * mfmt->depth)>>3; + -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER - }; ++ /* Image buffer has to be padded to allow for alignment, even though ++ * we then remove that padding before delivering the buffer. ++ */ ++ f->fmt.pix.sizeimage = ((f->fmt.pix.height+15)&~15) * ++ (((f->fmt.pix.width+31)&~31) * mfmt->depth) >> 3; ++ ++ if ((mfmt->flags & V4L2_FMT_FLAG_COMPRESSED) && ++ f->fmt.pix.sizeimage < MIN_BUFFER_SIZE) + f->fmt.pix.sizeimage = MIN_BUFFER_SIZE; - /** Valid mirror modes */ --- -1.9.3 - - -From cd4a9a53cc3d75612ca6e6cd17ac7b71e2c8bf27 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 19 Dec 2013 17:33:02 +0000 -Subject: [PATCH 065/124] V4L2: Fix JPEG timestamp issue - -JPEG images were coming through from the GPU with timestamp -of 0. Detect this and give current system time instead -of some invalid value. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 4766a9c..9fc90a2 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -238,7 +238,8 @@ static void buffer_cb(struct vchiq_mmal_instance *instance, - } +- if (mfmt->fourcc == V4L2_PIX_FMT_YUYV || +- mfmt->fourcc == V4L2_PIX_FMT_UYVY) +- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; +- else ++ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24) + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; ++ else ++ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + f->fmt.pix.priv = 0; + ++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, ++ "Now %dx%d format %08X\n", ++ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); ++ + v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix, + __func__); + return 0; +@@ -818,8 +952,8 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, + switch (mfmt->mmal_component) { + case MMAL_COMPONENT_CAMERA: + /* Make a further decision on port based on resolution */ +- if (f->fmt.pix.width <= MAX_VIDEO_MODE_WIDTH +- && f->fmt.pix.height <= MAX_VIDEO_MODE_HEIGHT) ++ if (f->fmt.pix.width <= max_video_width ++ && f->fmt.pix.height <= max_video_height) + camera_port = port = + &dev->component[MMAL_COMPONENT_CAMERA]-> + output[MMAL_CAMERA_PORT_VIDEO]; +@@ -861,8 +995,9 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, + camera_port->es.video.crop.y = 0; + camera_port->es.video.crop.width = f->fmt.pix.width; + camera_port->es.video.crop.height = f->fmt.pix.height; +- camera_port->es.video.frame_rate.num = 30; ++ camera_port->es.video.frame_rate.num = 0; + camera_port->es.video.frame_rate.den = 1; ++ camera_port->es.video.color_space = MMAL_COLOR_SPACE_JPEG_JFIF; + + ret = vchiq_mmal_port_set_format(dev->instance, camera_port); + +@@ -896,8 +1031,10 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, + preview_port->es.video.crop.y = 0; + preview_port->es.video.crop.width = f->fmt.pix.width; + preview_port->es.video.crop.height = f->fmt.pix.height; +- preview_port->es.video.frame_rate.num = 30; +- preview_port->es.video.frame_rate.den = 1; ++ preview_port->es.video.frame_rate.num = ++ dev->capture.timeperframe.denominator; ++ preview_port->es.video.frame_rate.den = ++ dev->capture.timeperframe.numerator; + ret = vchiq_mmal_port_set_format(dev->instance, preview_port); + if (overlay_enabled) { + ret = vchiq_mmal_port_connect_tunnel( +@@ -913,7 +1050,9 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, + + if (ret) { + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, +- "%s failed to set format\n", __func__); ++ "%s failed to set format %dx%d %08X\n", __func__, ++ f->fmt.pix.width, f->fmt.pix.height, ++ f->fmt.pix.pixelformat); + /* ensure capture is not going to be tried */ + dev->capture.port = NULL; } else { - if (dev->capture.frame_count) { -- if (dev->capture.vc_start_timestamp != -1) { -+ if (dev->capture.vc_start_timestamp != -1 && -+ pts != 0) { - s64 runtime_us = pts - - dev->capture.vc_start_timestamp; - u32 div = 0; -@@ -259,7 +260,7 @@ static void buffer_cb(struct vchiq_mmal_instance *instance, - USEC_PER_SEC; - } - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -- "Convert start time %d.%06d and %llu" -+ "Convert start time %d.%06d and %llu " - "with offset %llu to %d.%06d\n", - (int)dev->capture.kernel_start_ts. - tv_sec, --- -1.9.3 - - -From 442067cc37b21ff397d0a65894093d2f9ff80833 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 9 Dec 2013 11:24:55 +0000 -Subject: [PATCH 066/124] V4L2: Fix issue when switching down JPEG resolution. - -JPEG buffer size calculation is based on input resolution. -Input resolution was being configured after output port -format. Caused failures if switching from one JPEG resolution -to a smaller one. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 126 ++++++++++++++---------- - 1 file changed, 72 insertions(+), 54 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 9fc90a2..4780107 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -955,69 +955,87 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, +@@ -927,69 +1066,91 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, camera_port->current_buffer.num = camera_port->recommended_buffer.num; @@ -104563,8 +107914,12 @@ index 9fc90a2..4780107 100644 + if (ret) + v4l2_dbg(1, bcm2835_v4l2_debug, + &dev->v4l2_dev, -+ "%s failed to set format\n", -+ __func__); ++ "%s failed to set format %dx%d fmt %08X\n", ++ __func__, ++ f->fmt.pix.width, ++ f->fmt.pix.height, ++ f->fmt.pix.pixelformat ++ ); + } + + if (!ret) { @@ -104640,225 +107995,30 @@ index 9fc90a2..4780107 100644 } } else { /* configure buffering */ --- -1.9.3 - - -From a6395f30c0ab514fbabe160e9bcdbde0b93ee233 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 23 Dec 2013 15:42:21 +0000 -Subject: [PATCH 067/124] V4L2: Enable MJPEG encoding - -Requires GPU firmware update to support MJPEG encoder. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 7 +++++++ - drivers/media/platform/bcm2835/mmal-encodings.h | 1 + - 2 files changed, 8 insertions(+) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 4780107..166039e 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -100,6 +100,13 @@ static struct mmal_fmt formats[] = { - .mmal = MMAL_ENCODING_H264, - .depth = 8, - .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, -+ }, -+ { -+ .name = "MJPEG", -+ .fourcc = V4L2_PIX_FMT_MJPEG, -+ .mmal = MMAL_ENCODING_MJPEG, -+ .depth = 8, -+ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, - } - }; +@@ -1001,13 +1162,20 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, + if (!ret) { + dev->capture.fmt = mfmt; + dev->capture.stride = f->fmt.pix.bytesperline; +- dev->capture.width = port->es.video.crop.width; +- dev->capture.height = port->es.video.crop.height; ++ dev->capture.width = camera_port->es.video.crop.width; ++ dev->capture.height = camera_port->es.video.crop.height; ++ dev->capture.buffersize = port->current_buffer.size; -diff --git a/drivers/media/platform/bcm2835/mmal-encodings.h b/drivers/media/platform/bcm2835/mmal-encodings.h -index 856e80e..764bb12 100644 ---- a/drivers/media/platform/bcm2835/mmal-encodings.h -+++ b/drivers/media/platform/bcm2835/mmal-encodings.h -@@ -27,6 +27,7 @@ - #define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ') - #define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O') - #define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K') -+#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G') + /* select port for capture */ + dev->capture.port = port; + dev->capture.camera_port = camera_port; + dev->capture.encode_component = encode_component; ++ v4l2_dbg(1, bcm2835_v4l2_debug, ++ &dev->v4l2_dev, ++ "Set dev->capture.fmt %08X, %dx%d, stride %d, size %d", ++ port->format.encoding, ++ dev->capture.width, dev->capture.height, ++ dev->capture.stride, dev->capture.buffersize); + } + } - #define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G') - #define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ') --- -1.9.3 - - -From 2bcc02c1f08001b3a55a6d98ca1b5576b4c85d42 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 2 Jan 2014 15:57:06 +0000 -Subject: [PATCH 068/124] V4L2: Correct flag settings for compressed formats - -Set flags field correctly on enum_fmt_vid_cap for compressed -image formats. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 9 +++++++++ - drivers/media/platform/bcm2835/mmal-common.h | 1 + - 2 files changed, 10 insertions(+) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 166039e..7f99a14 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -69,6 +69,7 @@ static struct mmal_fmt formats[] = { - { - .name = "4:2:0, packed YUV", - .fourcc = V4L2_PIX_FMT_YUV420, -+ .flags = 0, - .mmal = MMAL_ENCODING_I420, - .depth = 12, - .mmal_component = MMAL_COMPONENT_CAMERA, -@@ -76,6 +77,7 @@ static struct mmal_fmt formats[] = { - { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, -+ .flags = 0, - .mmal = MMAL_ENCODING_YUYV, - .depth = 16, - .mmal_component = MMAL_COMPONENT_CAMERA, -@@ -83,6 +85,7 @@ static struct mmal_fmt formats[] = { - { - .name = "RGB24 (BE)", - .fourcc = V4L2_PIX_FMT_BGR24, -+ .flags = 0, - .mmal = MMAL_ENCODING_BGR24, - .depth = 24, - .mmal_component = MMAL_COMPONENT_CAMERA, -@@ -90,6 +93,7 @@ static struct mmal_fmt formats[] = { - { - .name = "JPEG", - .fourcc = V4L2_PIX_FMT_JPEG, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal = MMAL_ENCODING_JPEG, - .depth = 8, - .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE, -@@ -97,6 +101,7 @@ static struct mmal_fmt formats[] = { - { - .name = "H264", - .fourcc = V4L2_PIX_FMT_H264, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal = MMAL_ENCODING_H264, - .depth = 8, - .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, -@@ -104,6 +109,7 @@ static struct mmal_fmt formats[] = { - { - .name = "MJPEG", - .fourcc = V4L2_PIX_FMT_MJPEG, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal = MMAL_ENCODING_MJPEG, - .depth = 8, - .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, -@@ -555,6 +561,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, - - strlcpy(f->description, fmt->name, sizeof(f->description)); - f->pixelformat = fmt->fourcc; -+ f->flags = fmt->flags; - - return 0; - } -@@ -750,6 +757,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - - strlcpy(f->description, fmt->name, sizeof(f->description)); - f->pixelformat = fmt->fourcc; -+ f->flags = fmt->flags; -+ - return 0; - } - -diff --git a/drivers/media/platform/bcm2835/mmal-common.h b/drivers/media/platform/bcm2835/mmal-common.h -index 602b4a7..076f9a8 100644 ---- a/drivers/media/platform/bcm2835/mmal-common.h -+++ b/drivers/media/platform/bcm2835/mmal-common.h -@@ -26,6 +26,7 @@ - struct mmal_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ -+ int flags; /* v4l2 flags field */ - u32 mmal; - int depth; - u32 mmal_component; /* MMAL component index to be used to encode */ --- -1.9.3 - - -From ecabb465f431172a2aa19517bef7134b42debffe Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 12 Feb 2014 11:18:20 +0000 -Subject: [PATCH 069/124] V4L2: H264 profile & level ctrls, FPS control and - auto exp pri - -Several control handling updates. -H264 profile and level controls. -Timeperframe/FPS reworked to add V4L2_CID_EXPOSURE_AUTO_PRIORITY to -select whether AE is allowed to override the framerate specified. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 107 ++++++----- - drivers/media/platform/bcm2835/bcm2835-camera.h | 12 +- - drivers/media/platform/bcm2835/controls.c | 225 ++++++++++++++++++++++- - drivers/media/platform/bcm2835/mmal-parameters.h | 87 +++++++++ - 4 files changed, 383 insertions(+), 48 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 7f99a14..6d0d77a 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -36,7 +36,8 @@ - - #define BM2835_MMAL_VERSION "0.0.2" - #define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2" -- -+#define MIN_WIDTH 16 -+#define MIN_HEIGHT 16 - #define MAX_WIDTH 2592 - #define MAX_HEIGHT 1944 - #define MIN_BUFFER_SIZE (80*1024) -@@ -56,7 +57,7 @@ MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2"); - static struct bm2835_mmal_dev *gdev; /* global device data */ - - #define FPS_MIN 1 --#define FPS_MAX 30 -+#define FPS_MAX 90 - - /* timeperframe: min/max and default */ - static const struct v4l2_fract -@@ -903,10 +904,8 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - camera_port->es.video.crop.y = 0; - camera_port->es.video.crop.width = f->fmt.pix.width; - camera_port->es.video.crop.height = f->fmt.pix.height; -- camera_port->es.video.frame_rate.num = -- dev->capture.timeperframe.denominator; -- camera_port->es.video.frame_rate.den = -- dev->capture.timeperframe.numerator; -+ camera_port->es.video.frame_rate.num = 0; -+ camera_port->es.video.frame_rate.den = 1; - - ret = vchiq_mmal_port_set_format(dev->instance, camera_port); - -@@ -940,8 +939,10 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - preview_port->es.video.crop.y = 0; - preview_port->es.video.crop.width = f->fmt.pix.width; - preview_port->es.video.crop.height = f->fmt.pix.height; -- preview_port->es.video.frame_rate.num = 30; -- preview_port->es.video.frame_rate.den = 1; -+ preview_port->es.video.frame_rate.num = -+ dev->capture.timeperframe.denominator; -+ preview_port->es.video.frame_rate.den = -+ dev->capture.timeperframe.numerator; - ret = vchiq_mmal_port_set_format(dev->instance, preview_port); - if (overlay_enabled) { - ret = vchiq_mmal_port_connect_tunnel( -@@ -1116,22 +1117,56 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, +@@ -1048,14 +1216,115 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, } ret = mmal_setup_components(dev, f); @@ -104894,16 +108054,15 @@ index 7f99a14..6d0d77a 100644 + return 0; +} + - /* timeperframe is arbitrary and continous */ - static int vidioc_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fival) - { ++/* timeperframe is arbitrary and continous */ ++static int vidioc_enum_frameintervals(struct file *file, void *priv, ++ struct v4l2_frmivalenum *fival) ++{ + int i; + - if (fival->index) - return -EINVAL; - -- /* regarding width & height - we support any */ ++ if (fival->index) ++ return -EINVAL; ++ + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].fourcc == fival->pixel_format) + break; @@ -104914,85 +108073,170 @@ index 7f99a14..6d0d77a 100644 + if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH || + fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT) + return -EINVAL; - - fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; - -@@ -1167,7 +1202,6 @@ static int vidioc_s_parm(struct file *file, void *priv, - struct bm2835_mmal_dev *dev = video_drvdata(file); - struct v4l2_fract tpf; - struct mmal_parameter_rational fps_param; -- int ret; - - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; -@@ -1183,27 +1217,11 @@ static int vidioc_s_parm(struct file *file, void *priv, - parm->parm.capture.timeperframe = tpf; - parm->parm.capture.readbuffers = 1; - -- fps_param.num = dev->capture.timeperframe.denominator; -- fps_param.den = dev->capture.timeperframe.numerator; -- ret = vchiq_mmal_port_parameter_set(dev->instance, -- &dev->component[MMAL_COMPONENT_CAMERA]-> -- output[MMAL_CAMERA_PORT_PREVIEW], -- MMAL_PARAMETER_VIDEO_FRAME_RATE, -- &fps_param, sizeof(fps_param)); -- ret += vchiq_mmal_port_parameter_set(dev->instance, -- &dev->component[MMAL_COMPONENT_CAMERA]-> -- output[MMAL_CAMERA_PORT_VIDEO], -- MMAL_PARAMETER_VIDEO_FRAME_RATE, -- &fps_param, sizeof(fps_param)); -- ret += vchiq_mmal_port_parameter_set(dev->instance, -- &dev->component[MMAL_COMPONENT_CAMERA]-> -- output[MMAL_CAMERA_PORT_CAPTURE], -- MMAL_PARAMETER_VIDEO_FRAME_RATE, -- &fps_param, sizeof(fps_param)); -- if (ret) -- v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev, -- "Failed to set fps ret %d\n", -- ret); ++ ++ fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; ++ ++ /* fill in stepwise (step=1.0 is requred by V4L2 spec) */ ++ fival->stepwise.min = tpf_min; ++ fival->stepwise.max = tpf_max; ++ fival->stepwise.step = (struct v4l2_fract) {1, 1}; ++ ++ return 0; ++} ++ ++static int vidioc_g_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *parm) ++{ ++ struct bm2835_mmal_dev *dev = video_drvdata(file); ++ ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; ++ parm->parm.capture.timeperframe = dev->capture.timeperframe; ++ parm->parm.capture.readbuffers = 1; ++ return 0; ++} ++ ++#define FRACT_CMP(a, OP, b) \ ++ ((u64)(a).numerator * (b).denominator OP \ ++ (u64)(b).numerator * (a).denominator) ++ ++static int vidioc_s_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *parm) ++{ ++ struct bm2835_mmal_dev *dev = video_drvdata(file); ++ struct v4l2_fract tpf; ++ struct mmal_parameter_rational fps_param; ++ ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ ++ tpf = parm->parm.capture.timeperframe; ++ ++ /* tpf: {*, 0} resets timing; clip to [min, max]*/ ++ tpf = tpf.denominator ? tpf : tpf_default; ++ tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf; ++ tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf; ++ ++ dev->capture.timeperframe = tpf; ++ parm->parm.capture.timeperframe = tpf; ++ parm->parm.capture.readbuffers = 1; ++ + fps_param.num = 0; /* Select variable fps, and then use + * FPS_RANGE to select the actual limits. + */ + fps_param.den = 1; + set_framerate_params(dev); - - return 0; - } -@@ -1236,6 +1254,7 @@ static const struct v4l2_ioctl_ops camera0_ioctl_ops = { ++ ++ return 0; ++} ++ + static const struct v4l2_ioctl_ops camera0_ioctl_ops = { + /* overlay */ + .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, +@@ -1084,6 +1353,51 @@ static const struct v4l2_ioctl_ops camera0_ioctl_ops = { .vidioc_querybuf = vb2_ioctl_querybuf, .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_enum_framesizes = vidioc_enum_framesizes, - .vidioc_enum_frameintervals = vidioc_enum_frameintervals, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_s_parm = vidioc_s_parm, -@@ -1331,10 +1350,8 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) ++ .vidioc_enum_frameintervals = vidioc_enum_frameintervals, ++ .vidioc_g_parm = vidioc_g_parm, ++ .vidioc_s_parm = vidioc_s_parm, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ ++ .vidioc_log_status = v4l2_ctrl_log_status, ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++}; ++ ++static const struct v4l2_ioctl_ops camera0_ioctl_ops_gstreamer = { ++ /* overlay */ ++ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, ++ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, ++ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, ++ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, ++ .vidioc_overlay = vidioc_overlay, ++ .vidioc_g_fbuf = vidioc_g_fbuf, ++ ++ /* inputs */ ++ .vidioc_enum_input = vidioc_enum_input, ++ .vidioc_g_input = vidioc_g_input, ++ .vidioc_s_input = vidioc_s_input, ++ ++ /* capture */ ++ .vidioc_querycap = vidioc_querycap, ++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, ++ ++ /* buffer management */ ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ /* Remove this function ptr to fix gstreamer bug ++ .vidioc_enum_framesizes = vidioc_enum_framesizes, */ ++ .vidioc_enum_frameintervals = vidioc_enum_frameintervals, ++ .vidioc_g_parm = vidioc_g_parm, ++ .vidioc_s_parm = vidioc_s_parm, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + +@@ -1122,8 +1436,10 @@ static int set_camera_parameters(struct vchiq_mmal_instance *instance, + .max_stills_h = MAX_HEIGHT, + .stills_yuv422 = 1, + .one_shot_stills = 1, +- .max_preview_video_w = 1920, +- .max_preview_video_h = 1088, ++ .max_preview_video_w = (max_video_width > 1920) ? ++ max_video_width : 1920, ++ .max_preview_video_h = (max_video_height > 1088) ? ++ max_video_height : 1088, + .num_preview_video_frames = 3, + .stills_capture_circular_buffer_height = 0, + .fast_preview_resume = 0, +@@ -1141,6 +1457,7 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) + { + int ret; + struct mmal_es_format *format; ++ u32 bool_true = 1; + + ret = vchiq_mmal_init(&dev->instance); + if (ret < 0) +@@ -1176,8 +1493,8 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) format->es->video.crop.y = 0; format->es->video.crop.width = 1024; format->es->video.crop.height = 768; -- format->es->video.frame_rate.num = -- dev->capture.timeperframe.denominator; -- format->es->video.frame_rate.den = -- dev->capture.timeperframe.numerator; +- format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; +- format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; + format->es->video.frame_rate.num = 0; /* Rely on fps_range */ + format->es->video.frame_rate.den = 1; format = &dev->component[MMAL_COMPONENT_CAMERA]-> -@@ -1349,10 +1366,8 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) +@@ -1192,8 +1509,14 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) format->es->video.crop.y = 0; format->es->video.crop.width = 1024; format->es->video.crop.height = 768; -- format->es->video.frame_rate.num = -- dev->capture.timeperframe.denominator; -- format->es->video.frame_rate.den = -- dev->capture.timeperframe.numerator; +- format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; +- format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; + format->es->video.frame_rate.num = 0; /* Rely on fps_range */ + format->es->video.frame_rate.den = 1; ++ ++ vchiq_mmal_port_parameter_set(dev->instance, ++ &dev->component[MMAL_COMPONENT_CAMERA]-> ++ output[MMAL_CAMERA_PORT_VIDEO], ++ MMAL_PARAMETER_NO_IMAGE_PADDING, ++ &bool_true, sizeof(bool_true)); format = &dev->component[MMAL_COMPONENT_CAMERA]-> -@@ -1366,7 +1381,7 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) +@@ -1207,13 +1530,22 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) format->es->video.crop.y = 0; format->es->video.crop.width = 2592; format->es->video.crop.height = 1944; @@ -105001,16 +108245,22 @@ index 7f99a14..6d0d77a 100644 format->es->video.frame_rate.den = 1; dev->capture.width = format->es->video.width; -@@ -1374,6 +1389,8 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) + dev->capture.height = format->es->video.height; dev->capture.fmt = &formats[0]; dev->capture.encode_component = NULL; - dev->capture.timeperframe = tpf_default; ++ dev->capture.timeperframe = tpf_default; + dev->capture.enc_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; ++ ++ vchiq_mmal_port_parameter_set(dev->instance, ++ &dev->component[MMAL_COMPONENT_CAMERA]-> ++ output[MMAL_CAMERA_PORT_CAPTURE], ++ MMAL_PARAMETER_NO_IMAGE_PADDING, ++ &bool_true, sizeof(bool_true)); /* get the preview component ready */ ret = vchiq_mmal_component_init( -@@ -1420,6 +1437,14 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) +@@ -1260,6 +1592,14 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) } { @@ -105025,34 +108275,101 @@ index 7f99a14..6d0d77a 100644 unsigned int enable = 1; vchiq_mmal_port_parameter_set( dev->instance, +@@ -1312,6 +1652,11 @@ static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev, + int ret; + + *vfd = vdev_template; ++ if (gst_v4l2src_is_broken) { ++ v4l2_info(&dev->v4l2_dev, ++ "Work-around for gstreamer issue is active.\n"); ++ vfd->ioctl_ops = &camera0_ioctl_ops_gstreamer; ++ } + + vfd->v4l2_dev = &dev->v4l2_dev; + +@@ -1328,8 +1673,9 @@ static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev, + if (ret < 0) + return ret; + +- v4l2_info(vfd->v4l2_dev, "V4L2 device registered as %s\n", +- video_device_node_name(vfd)); ++ v4l2_info(vfd->v4l2_dev, ++ "V4L2 device registered as %s - stills mode > %dx%d\n", ++ video_device_node_name(vfd), max_video_width, max_video_height); + + return 0; + } +@@ -1337,9 +1683,9 @@ static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev, + static struct v4l2_format default_v4l2_format = { + .fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG, + .fmt.pix.width = 1024, +- .fmt.pix.bytesperline = 1024 * 3 / 2, ++ .fmt.pix.bytesperline = 1024, + .fmt.pix.height = 768, +- .fmt.pix.sizeimage = 1<<18, ++ .fmt.pix.sizeimage = 1024*768, + }; + + static int __init bm2835_mmal_init(void) +@@ -1402,6 +1748,9 @@ static int __init bm2835_mmal_init(void) + if (ret < 0) + goto unreg_dev; + ++ /* Really want to call vidioc_s_fmt_vid_cap with the default ++ * format, but currently the APIs don't join up. ++ */ + ret = mmal_setup_components(dev, &default_v4l2_format); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index 25aa91f..8822a1a 100644 +index 883eab7..7fe9f65 100644 --- a/drivers/media/platform/bcm2835/bcm2835-camera.h +++ b/drivers/media/platform/bcm2835/bcm2835-camera.h @@ -15,7 +15,7 @@ * core driver device */ --#define V4L2_CTRL_COUNT 21 /* number of v4l controls */ -+#define V4L2_CTRL_COUNT 24 /* number of v4l controls */ +-#define V4L2_CTRL_COUNT 18 /* number of v4l controls */ ++#define V4L2_CTRL_COUNT 28 /* number of v4l controls */ enum { MMAL_COMPONENT_CAMERA = 0, -@@ -49,7 +49,9 @@ struct bm2835_mmal_dev { +@@ -32,9 +32,6 @@ enum { + MMAL_CAMERA_PORT_COUNT + }; + +-#define PREVIEW_FRAME_RATE_NUM 30 +-#define PREVIEW_FRAME_RATE_DEN 1 +- + #define PREVIEW_LAYER 2 + + extern int bcm2835_v4l2_debug; +@@ -48,9 +45,19 @@ struct bm2835_mmal_dev { + /* controls */ + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *ctrls[V4L2_CTRL_COUNT]; ++ enum v4l2_scene_mode scene_mode; + struct mmal_colourfx colourfx; int hflip; int vflip; - enum mmal_parameter_exposuremode exposure_mode; -+ enum v4l2_exposure_auto_type exposure_mode_v4l2; - unsigned int manual_shutter_speed; ++ int red_gain; ++ int blue_gain; ++ enum mmal_parameter_exposuremode exposure_mode_user; ++ enum v4l2_exposure_auto_type exposure_mode_v4l2_user; ++ /* active exposure mode may differ if selected via a scene mode */ ++ enum mmal_parameter_exposuremode exposure_mode_active; ++ enum mmal_parameter_exposuremeteringmode metering_mode; ++ unsigned int manual_shutter_speed; + bool exp_auto_priority; /* allocated mmal instance and components */ struct vchiq_mmal_instance *instance; -@@ -63,12 +65,16 @@ struct bm2835_mmal_dev { +@@ -63,12 +70,18 @@ struct bm2835_mmal_dev { + unsigned int width; /* width */ unsigned int height; /* height */ unsigned int stride; /* stride */ ++ unsigned int buffersize; /* buffer size with padding */ struct mmal_fmt *fmt; -- struct v4l2_fract timeperframe; + struct v4l2_fract timeperframe; /* H264 encode bitrate */ @@ -105066,7 +108383,7 @@ index 25aa91f..8822a1a 100644 /* JPEG Q-factor */ int q_factor; -@@ -98,7 +104,7 @@ int bm2835_mmal_init_controls( +@@ -98,7 +111,7 @@ int bm2835_mmal_init_controls( struct v4l2_ctrl_handler *hdl); int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev); @@ -105076,10 +108393,50 @@ index 25aa91f..8822a1a 100644 /* Debug helpers */ diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index cb062a9..45cf790 100644 +index d1408e5..3017b94 100644 --- a/drivers/media/platform/bcm2835/controls.c +++ b/drivers/media/platform/bcm2835/controls.c -@@ -69,7 +69,6 @@ static const s64 bitrate_mode_qmenu[] = { +@@ -30,11 +30,23 @@ + #include "mmal-parameters.h" + #include "bcm2835-camera.h" + +-/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -24 to +24. +- * These are in 1/6th increments so the effective range is -4.0EV to +4.0EV. ++/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -4.0 to +4.0. ++ * MMAL values are in 1/6th increments so the MMAL range is -24 to +24. ++ * V4L2 docs say value "is expressed in terms of EV, drivers should interpret ++ * the values as 0.001 EV units, where the value 1000 stands for +1 EV." ++ * V4L2 is limited to a max of 32 values in a menu, so count in 1/3rds from ++ * -4 to +4 + */ + static const s64 ev_bias_qmenu[] = { +- -24, -21, -18, -15, -12, -9, -6, -3, 0, 3, 6, 9, 12, 15, 18, 21, 24 ++ -4000, -3667, -3333, ++ -3000, -2667, -2333, ++ -2000, -1667, -1333, ++ -1000, -667, -333, ++ 0, 333, 667, ++ 1000, 1333, 1667, ++ 2000, 2333, 2667, ++ 3000, 3333, 3667, ++ 4000 + }; + + /* Supported ISO values +@@ -44,13 +56,19 @@ static const s64 iso_qmenu[] = { + 0, 100, 200, 400, 800, + }; + ++static const s64 mains_freq_qmenu[] = { ++ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, ++ V4L2_CID_POWER_LINE_FREQUENCY_50HZ, ++ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, ++ V4L2_CID_POWER_LINE_FREQUENCY_AUTO ++}; ++ + /* Supported video encode modes */ + static const s64 bitrate_mode_qmenu[] = { + (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, }; @@ -105087,26 +108444,268 @@ index cb062a9..45cf790 100644 enum bm2835_mmal_ctrl_type { MMAL_CONTROL_TYPE_STD, MMAL_CONTROL_TYPE_STD_MENU, -@@ -329,6 +328,9 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev, +@@ -77,6 +95,7 @@ struct bm2835_mmal_v4l2_ctrl { + const s64 *imenu; /* integer menu array */ + u32 mmal_id; /* mmal parameter id */ + bm2835_mmal_v4l2_ctrl_cb *setter; ++ bool ignore_errors; + }; - } - dev->exposure_mode = exp_mode; -+ dev->exposure_mode_v4l2 = ctrl->val; -+ } else if (mmal_ctrl->id == V4L2_CID_EXPOSURE_AUTO_PRIORITY) { -+ dev->exp_auto_priority = ctrl->val; - } + struct v4l2_to_mmal_effects_setting { +@@ -126,6 +145,25 @@ static const struct v4l2_to_mmal_effects_setting + 1, 1, 0, 0, 0, {0, 0, 0, 0, 0} } + }; - if (dev->exposure_mode == MMAL_PARAM_EXPOSUREMODE_OFF) -@@ -340,6 +342,8 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev, - ret += vchiq_mmal_port_parameter_set(dev->instance, control, - MMAL_PARAMETER_EXPOSURE_MODE, - &exp_mode, sizeof(u32)); -+ ret += set_framerate_params(dev); ++struct v4l2_mmal_scene_config { ++ enum v4l2_scene_mode v4l2_scene; ++ enum mmal_parameter_exposuremode exposure_mode; ++ enum mmal_parameter_exposuremeteringmode metering_mode; ++}; + - return ret; ++static const struct v4l2_mmal_scene_config scene_configs[] = { ++ /* V4L2_SCENE_MODE_NONE automatically added */ ++ { ++ V4L2_SCENE_MODE_NIGHT, ++ MMAL_PARAM_EXPOSUREMODE_NIGHT, ++ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE ++ }, ++ { ++ V4L2_SCENE_MODE_SPORTS, ++ MMAL_PARAM_EXPOSUREMODE_SPORTS, ++ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE ++ }, ++}; + + /* control handlers*/ + +@@ -133,10 +171,7 @@ static int ctrl_set_rational(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) + { +- struct { +- s32 num; /**< Numerator */ +- s32 den; /**< Denominator */ +- } rational_value; ++ struct mmal_parameter_rational rational_value; + struct vchiq_mmal_port *control; + + control = &dev->component[MMAL_COMPONENT_CAMERA]->control; +@@ -166,6 +201,41 @@ static int ctrl_set_value(struct bm2835_mmal_dev *dev, + &u32_value, sizeof(u32_value)); } -@@ -540,8 +544,8 @@ static int ctrl_set_colfx(struct bm2835_mmal_dev *dev, ++static int ctrl_set_value_menu(struct bm2835_mmal_dev *dev, ++ struct v4l2_ctrl *ctrl, ++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) ++{ ++ u32 u32_value; ++ struct vchiq_mmal_port *control; ++ ++ if (ctrl->val > mmal_ctrl->max || ctrl->val < mmal_ctrl->min) ++ return 1; ++ ++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; ++ ++ u32_value = mmal_ctrl->imenu[ctrl->val]; ++ ++ return vchiq_mmal_port_parameter_set(dev->instance, control, ++ mmal_ctrl->mmal_id, ++ &u32_value, sizeof(u32_value)); ++} ++ ++static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev, ++ struct v4l2_ctrl *ctrl, ++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) ++{ ++ s32 s32_value; ++ struct vchiq_mmal_port *control; ++ ++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; ++ ++ s32_value = (ctrl->val-12)*2; /* Convert from index to 1/6ths */ ++ ++ return vchiq_mmal_port_parameter_set(dev->instance, control, ++ mmal_ctrl->mmal_id, ++ &s32_value, sizeof(s32_value)); ++} ++ + static int ctrl_set_rotate(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) +@@ -245,37 +315,97 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) + { +- u32 u32_value; ++ enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode_user; ++ u32 shutter_speed = 0; + struct vchiq_mmal_port *control; ++ int ret = 0; + + control = &dev->component[MMAL_COMPONENT_CAMERA]->control; + ++ if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) { ++ /* V4L2 is in 100usec increments. ++ * MMAL is 1usec. ++ */ ++ dev->manual_shutter_speed = ctrl->val * 100; ++ } else if (mmal_ctrl->mmal_id == MMAL_PARAMETER_EXPOSURE_MODE) { ++ switch (ctrl->val) { ++ case V4L2_EXPOSURE_AUTO: ++ exp_mode = MMAL_PARAM_EXPOSUREMODE_AUTO; ++ break; ++ ++ case V4L2_EXPOSURE_MANUAL: ++ exp_mode = MMAL_PARAM_EXPOSUREMODE_OFF; ++ break; ++ } ++ dev->exposure_mode_user = exp_mode; ++ dev->exposure_mode_v4l2_user = ctrl->val; ++ } else if (mmal_ctrl->id == V4L2_CID_EXPOSURE_AUTO_PRIORITY) { ++ dev->exp_auto_priority = ctrl->val; ++ } ++ ++ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) { ++ if (exp_mode == MMAL_PARAM_EXPOSUREMODE_OFF) ++ shutter_speed = dev->manual_shutter_speed; ++ ++ ret = vchiq_mmal_port_parameter_set(dev->instance, ++ control, ++ MMAL_PARAMETER_SHUTTER_SPEED, ++ &shutter_speed, ++ sizeof(shutter_speed)); ++ ret += vchiq_mmal_port_parameter_set(dev->instance, ++ control, ++ MMAL_PARAMETER_EXPOSURE_MODE, ++ &exp_mode, ++ sizeof(u32)); ++ dev->exposure_mode_active = exp_mode; ++ } ++ /* exposure_dynamic_framerate (V4L2_CID_EXPOSURE_AUTO_PRIORITY) should ++ * always apply irrespective of scene mode. ++ */ ++ ret += set_framerate_params(dev); ++ ++ return ret; ++} ++ ++static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev, ++ struct v4l2_ctrl *ctrl, ++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) ++{ + switch (ctrl->val) { +- case V4L2_EXPOSURE_AUTO: +- u32_value = MMAL_PARAM_EXPOSUREMODE_AUTO; ++ case V4L2_EXPOSURE_METERING_AVERAGE: ++ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + break; + +- case V4L2_EXPOSURE_MANUAL: +- u32_value = MMAL_PARAM_EXPOSUREMODE_OFF; ++ case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: ++ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT; + break; + +- case V4L2_EXPOSURE_SHUTTER_PRIORITY: +- u32_value = MMAL_PARAM_EXPOSUREMODE_SPORTS; ++ case V4L2_EXPOSURE_METERING_SPOT: ++ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT; + break; + +- case V4L2_EXPOSURE_APERTURE_PRIORITY: +- u32_value = MMAL_PARAM_EXPOSUREMODE_NIGHT; ++ /* todo matrix weighting not added to Linux API till 3.9 ++ case V4L2_EXPOSURE_METERING_MATRIX: ++ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX; + break; ++ */ + + } + +- /* todo: what about the other ten modes there are MMAL parameters for */ +- return vchiq_mmal_port_parameter_set(dev->instance, control, ++ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) { ++ struct vchiq_mmal_port *control; ++ u32 u32_value = dev->metering_mode; ++ ++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; ++ ++ return vchiq_mmal_port_parameter_set(dev->instance, control, + mmal_ctrl->mmal_id, + &u32_value, sizeof(u32_value)); ++ } else ++ return 0; + } + +-static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev, ++static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) + { +@@ -285,24 +415,18 @@ static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev, + control = &dev->component[MMAL_COMPONENT_CAMERA]->control; + + switch (ctrl->val) { +- case V4L2_EXPOSURE_METERING_AVERAGE: +- u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; ++ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: ++ u32_value = MMAL_PARAM_FLICKERAVOID_OFF; + break; +- +- case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: +- u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT; ++ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: ++ u32_value = MMAL_PARAM_FLICKERAVOID_50HZ; + break; +- +- case V4L2_EXPOSURE_METERING_SPOT: +- u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT; ++ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: ++ u32_value = MMAL_PARAM_FLICKERAVOID_60HZ; + break; +- +- /* todo matrix weighting not added to Linux API till 3.9 +- case V4L2_EXPOSURE_METERING_MATRIX: +- u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX; ++ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: ++ u32_value = MMAL_PARAM_FLICKERAVOID_AUTO; + break; +- */ +- + } + + return vchiq_mmal_port_parameter_set(dev->instance, control, +@@ -367,6 +491,29 @@ static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev, + &u32_value, sizeof(u32_value)); + } + ++static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev, ++ struct v4l2_ctrl *ctrl, ++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) ++{ ++ struct vchiq_mmal_port *control; ++ struct mmal_parameter_awbgains gains; ++ ++ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; ++ ++ if (ctrl->id == V4L2_CID_RED_BALANCE) ++ dev->red_gain = ctrl->val; ++ else if (ctrl->id == V4L2_CID_BLUE_BALANCE) ++ dev->blue_gain = ctrl->val; ++ ++ gains.r_gain.num = dev->red_gain; ++ gains.b_gain.num = dev->blue_gain; ++ gains.r_gain.den = gains.b_gain.den = 1000; ++ ++ return vchiq_mmal_port_parameter_set(dev->instance, control, ++ mmal_ctrl->mmal_id, ++ &gains, sizeof(gains)); ++} ++ + static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) +@@ -443,8 +590,8 @@ static int ctrl_set_colfx(struct bm2835_mmal_dev *dev, &dev->colourfx, sizeof(dev->colourfx)); v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, @@ -105117,10 +108716,35 @@ index cb062a9..45cf790 100644 (ret == 0 ? 0 : -EINVAL)); return (ret == 0 ? 0 : EINVAL); } -@@ -623,6 +627,117 @@ static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev, +@@ -494,7 +641,7 @@ static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev, + return 0; + } + +-static int ctrl_set_q_factor(struct bm2835_mmal_dev *dev, ++static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) + { +@@ -510,12 +657,247 @@ static int ctrl_set_q_factor(struct bm2835_mmal_dev *dev, &u32_value, sizeof(u32_value)); } ++static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev, ++ struct v4l2_ctrl *ctrl, ++ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) ++{ ++ u32 u32_value; ++ struct vchiq_mmal_port *vid_enc_ctl; ++ ++ vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0]; ++ ++ u32_value = ctrl->val; ++ ++ return vchiq_mmal_port_parameter_set(dev->instance, vid_enc_ctl, ++ mmal_ctrl->mmal_id, ++ &u32_value, sizeof(u32_value)); ++} ++ +static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) @@ -105232,572 +108856,6 @@ index cb062a9..45cf790 100644 + return ret; +} + - static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl) - { - struct bm2835_mmal_dev *dev = -@@ -639,6 +754,9 @@ static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl) - } - - ret = mmal_ctrl->setter(dev, ctrl, mmal_ctrl); -+ if (ret) -+ pr_warn("ctrl id:%d/MMAL param %08X- returned ret %d\n", -+ ctrl->id, mmal_ctrl->mmal_id, ret); - if (mmal_ctrl->ignore_errors) - ret = 0; - return ret; -@@ -725,6 +843,14 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - false - }, - { -+ V4L2_CID_EXPOSURE_AUTO_PRIORITY, MMAL_CONTROL_TYPE_STD, -+ 0, 1, -+ 0, 1, NULL, -+ 0, /* Dummy MMAL ID as it gets mapped into FPS range*/ -+ &ctrl_set_exposure, -+ false -+ }, -+ { - V4L2_CID_EXPOSURE_METERING, - MMAL_CONTROL_TYPE_STD_MENU, - ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL, -@@ -814,6 +940,39 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - &ctrl_set_video_encode_param_output, - true /* Errors ignored as requires latest firmware to work */ - }, -+ { -+ V4L2_CID_MPEG_VIDEO_H264_PROFILE, -+ MMAL_CONTROL_TYPE_STD_MENU, -+ ~((1<ctrls[c]) && (v4l2_ctrls[c].setter)) { - ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c], - &v4l2_ctrls[c]); -- if (!v4l2_ctrls[c]. ignore_errors && ret) -+ if (!v4l2_ctrls[c].ignore_errors && ret) { -+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -+ "Failed when setting default values for ctrl %d\n", -+ c); - break; -+ } - } - } - return ret; - } - -+int set_framerate_params(struct bm2835_mmal_dev *dev) -+{ -+ struct mmal_parameter_fps_range fps_range; -+ int ret; -+ -+ if ((dev->exposure_mode_v4l2 == V4L2_EXPOSURE_AUTO || -+ dev->exposure_mode_v4l2 == V4L2_EXPOSURE_APERTURE_PRIORITY) && -+ (dev->exp_auto_priority)) { -+ /* Variable FPS. Define min FPS as 1fps. -+ * Max as max defined FPS. -+ */ -+ fps_range.fps_low.num = 1; -+ fps_range.fps_low.den = 1; -+ fps_range.fps_high.num = dev->capture.timeperframe.denominator; -+ fps_range.fps_high.den = dev->capture.timeperframe.numerator; -+ } else { -+ /* Fixed FPS - set min and max to be the same */ -+ fps_range.fps_low.num = fps_range.fps_high.num = -+ dev->capture.timeperframe.denominator; -+ fps_range.fps_low.den = fps_range.fps_high.den = -+ dev->capture.timeperframe.numerator; -+ } -+ -+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -+ "Set fps range to %d/%d to %d/%d\n", -+ fps_range.fps_low.num, -+ fps_range.fps_low.den, -+ fps_range.fps_high.num, -+ fps_range.fps_high.den -+ ); -+ -+ ret = vchiq_mmal_port_parameter_set(dev->instance, -+ &dev->component[MMAL_COMPONENT_CAMERA]-> -+ output[MMAL_CAMERA_PORT_PREVIEW], -+ MMAL_PARAMETER_FPS_RANGE, -+ &fps_range, sizeof(fps_range)); -+ ret += vchiq_mmal_port_parameter_set(dev->instance, -+ &dev->component[MMAL_COMPONENT_CAMERA]-> -+ output[MMAL_CAMERA_PORT_VIDEO], -+ MMAL_PARAMETER_FPS_RANGE, -+ &fps_range, sizeof(fps_range)); -+ ret += vchiq_mmal_port_parameter_set(dev->instance, -+ &dev->component[MMAL_COMPONENT_CAMERA]-> -+ output[MMAL_CAMERA_PORT_CAPTURE], -+ MMAL_PARAMETER_FPS_RANGE, -+ &fps_range, sizeof(fps_range)); -+ if (ret) -+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev, -+ "Failed to set fps ret %d\n", -+ ret); -+ -+ return ret; -+ -+} - int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl_handler *hdl) - { -diff --git a/drivers/media/platform/bcm2835/mmal-parameters.h b/drivers/media/platform/bcm2835/mmal-parameters.h -index b08a4b0..ae8fef9 100644 ---- a/drivers/media/platform/bcm2835/mmal-parameters.h -+++ b/drivers/media/platform/bcm2835/mmal-parameters.h -@@ -182,6 +182,14 @@ enum mmal_parameter_camera_config_timestamp_mode { - */ - }; - -+struct mmal_parameter_fps_range { -+ /**< Low end of the permitted framerate range */ -+ struct mmal_parameter_rational fps_low; -+ /**< High end of the permitted framerate range */ -+ struct mmal_parameter_rational fps_high; -+}; -+ -+ - /* camera configuration parameter */ - struct mmal_parameter_camera_config { - /* Parameters for setting up the image pools */ -@@ -293,6 +301,85 @@ enum mmal_parameter_rate_control_mode { - MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES - }; - -+enum mmal_video_profile { -+ MMAL_VIDEO_PROFILE_H263_BASELINE, -+ MMAL_VIDEO_PROFILE_H263_H320CODING, -+ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE, -+ MMAL_VIDEO_PROFILE_H263_ISWV2, -+ MMAL_VIDEO_PROFILE_H263_ISWV3, -+ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION, -+ MMAL_VIDEO_PROFILE_H263_INTERNET, -+ MMAL_VIDEO_PROFILE_H263_INTERLACE, -+ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY, -+ MMAL_VIDEO_PROFILE_MP4V_SIMPLE, -+ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE, -+ MMAL_VIDEO_PROFILE_MP4V_CORE, -+ MMAL_VIDEO_PROFILE_MP4V_MAIN, -+ MMAL_VIDEO_PROFILE_MP4V_NBIT, -+ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE, -+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE, -+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA, -+ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED, -+ MMAL_VIDEO_PROFILE_MP4V_HYBRID, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME, -+ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE, -+ MMAL_VIDEO_PROFILE_H264_BASELINE, -+ MMAL_VIDEO_PROFILE_H264_MAIN, -+ MMAL_VIDEO_PROFILE_H264_EXTENDED, -+ MMAL_VIDEO_PROFILE_H264_HIGH, -+ MMAL_VIDEO_PROFILE_H264_HIGH10, -+ MMAL_VIDEO_PROFILE_H264_HIGH422, -+ MMAL_VIDEO_PROFILE_H264_HIGH444, -+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE, -+ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF -+}; -+ -+enum mmal_video_level { -+ MMAL_VIDEO_LEVEL_H263_10, -+ MMAL_VIDEO_LEVEL_H263_20, -+ MMAL_VIDEO_LEVEL_H263_30, -+ MMAL_VIDEO_LEVEL_H263_40, -+ MMAL_VIDEO_LEVEL_H263_45, -+ MMAL_VIDEO_LEVEL_H263_50, -+ MMAL_VIDEO_LEVEL_H263_60, -+ MMAL_VIDEO_LEVEL_H263_70, -+ MMAL_VIDEO_LEVEL_MP4V_0, -+ MMAL_VIDEO_LEVEL_MP4V_0b, -+ MMAL_VIDEO_LEVEL_MP4V_1, -+ MMAL_VIDEO_LEVEL_MP4V_2, -+ MMAL_VIDEO_LEVEL_MP4V_3, -+ MMAL_VIDEO_LEVEL_MP4V_4, -+ MMAL_VIDEO_LEVEL_MP4V_4a, -+ MMAL_VIDEO_LEVEL_MP4V_5, -+ MMAL_VIDEO_LEVEL_MP4V_6, -+ MMAL_VIDEO_LEVEL_H264_1, -+ MMAL_VIDEO_LEVEL_H264_1b, -+ MMAL_VIDEO_LEVEL_H264_11, -+ MMAL_VIDEO_LEVEL_H264_12, -+ MMAL_VIDEO_LEVEL_H264_13, -+ MMAL_VIDEO_LEVEL_H264_2, -+ MMAL_VIDEO_LEVEL_H264_21, -+ MMAL_VIDEO_LEVEL_H264_22, -+ MMAL_VIDEO_LEVEL_H264_3, -+ MMAL_VIDEO_LEVEL_H264_31, -+ MMAL_VIDEO_LEVEL_H264_32, -+ MMAL_VIDEO_LEVEL_H264_4, -+ MMAL_VIDEO_LEVEL_H264_41, -+ MMAL_VIDEO_LEVEL_H264_42, -+ MMAL_VIDEO_LEVEL_H264_5, -+ MMAL_VIDEO_LEVEL_H264_51, -+ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF -+}; -+ -+struct mmal_parameter_video_profile { -+ enum mmal_video_profile profile; -+ enum mmal_video_level level; -+}; -+ - /* video parameters */ - - enum mmal_parameter_video_type { --- -1.9.3 - - -From a7d677b23a6cb5bb6e32f0d3a922792ad83c039a Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 12 Feb 2014 11:39:20 +0000 -Subject: [PATCH 070/124] V4L2: Correct BGR24 to RGB24 in format table - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 6d0d77a..8285e6a 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -84,8 +84,8 @@ static struct mmal_fmt formats[] = { - .mmal_component = MMAL_COMPONENT_CAMERA, - }, - { -- .name = "RGB24 (BE)", -- .fourcc = V4L2_PIX_FMT_BGR24, -+ .name = "RGB24 (LE)", -+ .fourcc = V4L2_PIX_FMT_RGB24, - .flags = 0, - .mmal = MMAL_ENCODING_BGR24, - .depth = 24, --- -1.9.3 - - -From 0aa372ffa22d147510e6998228c504546dc8d57d Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 12 Feb 2014 15:35:41 +0000 -Subject: [PATCH 071/124] V4L2: Add additional pixel formats. Correct - colourspace - -Adds the other flavours of YUYV, and NV12. -Corrects the overlay advertised colourspace. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 36 +++++++++++++++++++++++-- - 1 file changed, 34 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 8285e6a..3dea993 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -114,7 +114,39 @@ static struct mmal_fmt formats[] = { - .mmal = MMAL_ENCODING_MJPEG, - .depth = 8, - .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE, -- } -+ }, -+ { -+ .name = "4:2:2, packed, YVYU", -+ .fourcc = V4L2_PIX_FMT_YVYU, -+ .flags = 0, -+ .mmal = MMAL_ENCODING_YVYU, -+ .depth = 16, -+ .mmal_component = MMAL_COMPONENT_CAMERA, -+ }, -+ { -+ .name = "4:2:2, packed, VYUY", -+ .fourcc = V4L2_PIX_FMT_VYUY, -+ .flags = 0, -+ .mmal = MMAL_ENCODING_VYUY, -+ .depth = 16, -+ .mmal_component = MMAL_COMPONENT_CAMERA, -+ }, -+ { -+ .name = "4:2:2, packed, UYVY", -+ .fourcc = V4L2_PIX_FMT_UYVY, -+ .flags = 0, -+ .mmal = MMAL_ENCODING_UYVY, -+ .depth = 16, -+ .mmal_component = MMAL_COMPONENT_CAMERA, -+ }, -+ { -+ .name = "4:2:0, packed, NV12", -+ .fourcc = V4L2_PIX_FMT_NV12, -+ .flags = 0, -+ .mmal = MMAL_ENCODING_NV12, -+ .depth = 12, -+ .mmal_component = MMAL_COMPONENT_CAMERA, -+ }, - }; - - static struct mmal_fmt *get_format(struct v4l2_format *f) -@@ -691,7 +723,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh, - a->fmt.bytesperline = (preview_port->es.video.width * 3)>>1; - a->fmt.sizeimage = (preview_port->es.video.width * - preview_port->es.video.height * 3)>>1; -- a->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; -+ a->fmt.colorspace = V4L2_COLORSPACE_JPEG; - - return 0; - } --- -1.9.3 - - -From 50715361e65539e367c473e3f4df292d3e8344a3 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 14 Feb 2014 17:08:18 +0000 -Subject: [PATCH 072/124] V4L2: Drop logging msg from info to debug - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/mmal-vchiq.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/platform/bcm2835/mmal-vchiq.c b/drivers/media/platform/bcm2835/mmal-vchiq.c -index a06fb44..82752e6 100644 ---- a/drivers/media/platform/bcm2835/mmal-vchiq.c -+++ b/drivers/media/platform/bcm2835/mmal-vchiq.c -@@ -1326,7 +1326,7 @@ static int port_parameter_get(struct vchiq_mmal_instance *instance, - memcpy(value, &rmsg->u.port_parameter_get_reply.value, - rmsg->u.port_parameter_get_reply.size); - -- pr_info("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, -+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, - ret, port->component->handle, port->handle, parameter_id); - - release_msg: --- -1.9.3 - - -From 87a5cc23040a3c6e264c90729b6208654d2537e6 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 14 Feb 2014 17:12:08 +0000 -Subject: [PATCH 073/124] V4L2: Initial pass at scene modes. - -Only supports exposure mode and metering modes. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.h | 10 +- - drivers/media/platform/bcm2835/controls.c | 225 ++++++++++++++++++++---- - 2 files changed, 199 insertions(+), 36 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index 8822a1a..f389bea 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.h -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h -@@ -15,7 +15,7 @@ - * core driver device - */ - --#define V4L2_CTRL_COUNT 24 /* number of v4l controls */ -+#define V4L2_CTRL_COUNT 25 /* number of v4l controls */ - - enum { - MMAL_COMPONENT_CAMERA = 0, -@@ -45,11 +45,15 @@ struct bm2835_mmal_dev { - /* controls */ - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl *ctrls[V4L2_CTRL_COUNT]; -+ enum v4l2_scene_mode scene_mode; - struct mmal_colourfx colourfx; - int hflip; - int vflip; -- enum mmal_parameter_exposuremode exposure_mode; -- enum v4l2_exposure_auto_type exposure_mode_v4l2; -+ enum mmal_parameter_exposuremode exposure_mode_user; -+ enum v4l2_exposure_auto_type exposure_mode_v4l2_user; -+ /* active exposure mode may differ if selected via a scene mode */ -+ enum mmal_parameter_exposuremode exposure_mode_active; -+ enum mmal_parameter_exposuremeteringmode metering_mode; - unsigned int manual_shutter_speed; - bool exp_auto_priority; - -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index 45cf790..b7a7e883 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -145,6 +145,25 @@ static const struct v4l2_to_mmal_effects_setting - 1, 1, 0, 0, 0, {0, 0, 0, 0, 0} } - }; - -+struct v4l2_mmal_scene_config { -+ enum v4l2_scene_mode v4l2_scene; -+ enum mmal_parameter_exposuremode exposure_mode; -+ enum mmal_parameter_exposuremeteringmode metering_mode; -+}; -+ -+static const struct v4l2_mmal_scene_config scene_configs[] = { -+ /* V4L2_SCENE_MODE_NONE automatically added */ -+ { -+ V4L2_SCENE_MODE_NIGHT, -+ MMAL_PARAM_EXPOSUREMODE_NIGHT, -+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE -+ }, -+ { -+ V4L2_SCENE_MODE_SPORTS, -+ MMAL_PARAM_EXPOSUREMODE_SPORTS, -+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE -+ }, -+}; - - /* control handlers*/ - -@@ -296,7 +315,7 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) - { -- enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode; -+ enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode_user; - u32 shutter_speed = 0; - struct vchiq_mmal_port *control; - int ret = 0; -@@ -317,31 +336,32 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev, - case V4L2_EXPOSURE_MANUAL: - exp_mode = MMAL_PARAM_EXPOSUREMODE_OFF; - break; -- -- case V4L2_EXPOSURE_SHUTTER_PRIORITY: -- exp_mode = MMAL_PARAM_EXPOSUREMODE_SPORTS; -- break; -- -- case V4L2_EXPOSURE_APERTURE_PRIORITY: -- exp_mode = MMAL_PARAM_EXPOSUREMODE_NIGHT; -- break; -- - } -- dev->exposure_mode = exp_mode; -- dev->exposure_mode_v4l2 = ctrl->val; -+ dev->exposure_mode_user = exp_mode; -+ dev->exposure_mode_v4l2_user = ctrl->val; - } else if (mmal_ctrl->id == V4L2_CID_EXPOSURE_AUTO_PRIORITY) { - dev->exp_auto_priority = ctrl->val; - } - -- if (dev->exposure_mode == MMAL_PARAM_EXPOSUREMODE_OFF) -- shutter_speed = dev->manual_shutter_speed; -+ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) { -+ if (exp_mode == MMAL_PARAM_EXPOSUREMODE_OFF) -+ shutter_speed = dev->manual_shutter_speed; - -- ret = vchiq_mmal_port_parameter_set(dev->instance, control, -- MMAL_PARAMETER_SHUTTER_SPEED, -- &shutter_speed, sizeof(shutter_speed)); -- ret += vchiq_mmal_port_parameter_set(dev->instance, control, -- MMAL_PARAMETER_EXPOSURE_MODE, -- &exp_mode, sizeof(u32)); -+ ret = vchiq_mmal_port_parameter_set(dev->instance, -+ control, -+ MMAL_PARAMETER_SHUTTER_SPEED, -+ &shutter_speed, -+ sizeof(shutter_speed)); -+ ret += vchiq_mmal_port_parameter_set(dev->instance, -+ control, -+ MMAL_PARAMETER_EXPOSURE_MODE, -+ &exp_mode, -+ sizeof(u32)); -+ dev->exposure_mode_active = exp_mode; -+ } -+ /* exposure_dynamic_framerate (V4L2_CID_EXPOSURE_AUTO_PRIORITY) should -+ * always apply irrespective of scene mode. -+ */ - ret += set_framerate_params(dev); - - return ret; -@@ -351,35 +371,38 @@ static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) - { -- u32 u32_value; -- struct vchiq_mmal_port *control; -- -- control = &dev->component[MMAL_COMPONENT_CAMERA]->control; -- - switch (ctrl->val) { - case V4L2_EXPOSURE_METERING_AVERAGE: -- u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; -+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; - break; - - case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: -- u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT; -+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT; - break; - - case V4L2_EXPOSURE_METERING_SPOT: -- u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT; -+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT; - break; - - /* todo matrix weighting not added to Linux API till 3.9 - case V4L2_EXPOSURE_METERING_MATRIX: -- u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX; -+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX; - break; - */ - - } - -- return vchiq_mmal_port_parameter_set(dev->instance, control, -+ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) { -+ struct vchiq_mmal_port *control; -+ u32 u32_value = dev->metering_mode; -+ -+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; -+ -+ return vchiq_mmal_port_parameter_set(dev->instance, control, - mmal_ctrl->mmal_id, - &u32_value, sizeof(u32_value)); -+ } else -+ return 0; - } - - static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev, -@@ -738,6 +761,113 @@ static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev, - return ret; - } - +static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) @@ -105908,10 +108966,269 @@ index 45cf790..b7a7e883 100644 static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl) { struct bm2835_mmal_dev *dev = -@@ -973,6 +1103,15 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - &ctrl_set_video_encode_profile_level, - false + container_of(ctrl->handler, struct bm2835_mmal_dev, + ctrl_handler); + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl = ctrl->priv; ++ int ret; + + if ((mmal_ctrl == NULL) || + (mmal_ctrl->id != ctrl->id) || +@@ -524,7 +906,13 @@ static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl) + return -EINVAL; + } + +- return mmal_ctrl->setter(dev, ctrl, mmal_ctrl); ++ ret = mmal_ctrl->setter(dev, ctrl, mmal_ctrl); ++ if (ret) ++ pr_warn("ctrl id:%d/MMAL param %08X- returned ret %d\n", ++ ctrl->id, mmal_ctrl->mmal_id, ret); ++ if (mmal_ctrl->ignore_errors) ++ ret = 0; ++ return ret; + } + + static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = { +@@ -537,40 +925,54 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { + { + V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD, + -100, 100, 0, 1, NULL, +- MMAL_PARAMETER_SATURATION, &ctrl_set_rational ++ MMAL_PARAMETER_SATURATION, ++ &ctrl_set_rational, ++ false }, + { + V4L2_CID_SHARPNESS, MMAL_CONTROL_TYPE_STD, + -100, 100, 0, 1, NULL, +- MMAL_PARAMETER_SHARPNESS, &ctrl_set_rational ++ MMAL_PARAMETER_SHARPNESS, ++ &ctrl_set_rational, ++ false + }, + { + V4L2_CID_CONTRAST, MMAL_CONTROL_TYPE_STD, + -100, 100, 0, 1, NULL, +- MMAL_PARAMETER_CONTRAST, &ctrl_set_rational ++ MMAL_PARAMETER_CONTRAST, ++ &ctrl_set_rational, ++ false + }, + { + V4L2_CID_BRIGHTNESS, MMAL_CONTROL_TYPE_STD, + 0, 100, 50, 1, NULL, +- MMAL_PARAMETER_BRIGHTNESS, &ctrl_set_rational ++ MMAL_PARAMETER_BRIGHTNESS, ++ &ctrl_set_rational, ++ false + }, + { + V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU, + 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu, +- MMAL_PARAMETER_ISO, &ctrl_set_value ++ MMAL_PARAMETER_ISO, ++ &ctrl_set_value_menu, ++ false + }, + { + V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD, + 0, 1, 0, 1, NULL, +- MMAL_PARAMETER_VIDEO_STABILISATION, &ctrl_set_value ++ MMAL_PARAMETER_VIDEO_STABILISATION, ++ &ctrl_set_value, ++ false + }, + /* { + 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL +- }, +-*/ { ++ }, */ ++ { + V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU, + ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL, +- MMAL_PARAMETER_EXPOSURE_MODE, &ctrl_set_exposure ++ MMAL_PARAMETER_EXPOSURE_MODE, ++ &ctrl_set_exposure, ++ false + }, + /* todo this needs mixing in with set exposure + { +@@ -578,83 +980,258 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { + }, + */ + { ++ V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD, ++ /* Units of 100usecs */ ++ 1, 1*1000*10, 100*10, 1, NULL, ++ MMAL_PARAMETER_SHUTTER_SPEED, ++ &ctrl_set_exposure, ++ false ++ }, ++ { + V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU, + 0, ARRAY_SIZE(ev_bias_qmenu) - 1, + (ARRAY_SIZE(ev_bias_qmenu)+1)/2 - 1, 0, ev_bias_qmenu, +- MMAL_PARAMETER_EXPOSURE_COMP, &ctrl_set_value ++ MMAL_PARAMETER_EXPOSURE_COMP, ++ &ctrl_set_value_ev, ++ false ++ }, ++ { ++ V4L2_CID_EXPOSURE_AUTO_PRIORITY, MMAL_CONTROL_TYPE_STD, ++ 0, 1, ++ 0, 1, NULL, ++ 0, /* Dummy MMAL ID as it gets mapped into FPS range*/ ++ &ctrl_set_exposure, ++ false + }, + { + V4L2_CID_EXPOSURE_METERING, + MMAL_CONTROL_TYPE_STD_MENU, + ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL, +- MMAL_PARAMETER_EXP_METERING_MODE, &ctrl_set_metering_mode ++ MMAL_PARAMETER_EXP_METERING_MODE, ++ &ctrl_set_metering_mode, ++ false + }, + { + V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, + MMAL_CONTROL_TYPE_STD_MENU, +- ~0x3fe, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL, +- MMAL_PARAMETER_AWB_MODE, &ctrl_set_awb_mode ++ ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL, ++ MMAL_PARAMETER_AWB_MODE, ++ &ctrl_set_awb_mode, ++ false ++ }, ++ { ++ V4L2_CID_RED_BALANCE, MMAL_CONTROL_TYPE_STD, ++ 1, 7999, 1000, 1, NULL, ++ MMAL_PARAMETER_CUSTOM_AWB_GAINS, ++ &ctrl_set_awb_gains, ++ false ++ }, ++ { ++ V4L2_CID_BLUE_BALANCE, MMAL_CONTROL_TYPE_STD, ++ 1, 7999, 1000, 1, NULL, ++ MMAL_PARAMETER_CUSTOM_AWB_GAINS, ++ &ctrl_set_awb_gains, ++ false + }, + { + V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU, + 0, 15, V4L2_COLORFX_NONE, 0, NULL, +- MMAL_PARAMETER_IMAGE_EFFECT, &ctrl_set_image_effect ++ MMAL_PARAMETER_IMAGE_EFFECT, ++ &ctrl_set_image_effect, ++ false + }, + { + V4L2_CID_COLORFX_CBCR, MMAL_CONTROL_TYPE_STD, + 0, 0xffff, 0x8080, 1, NULL, +- MMAL_PARAMETER_COLOUR_EFFECT, &ctrl_set_colfx ++ MMAL_PARAMETER_COLOUR_EFFECT, ++ &ctrl_set_colfx, ++ false + }, + { + V4L2_CID_ROTATE, MMAL_CONTROL_TYPE_STD, + 0, 360, 0, 90, NULL, +- MMAL_PARAMETER_ROTATION, &ctrl_set_rotate ++ MMAL_PARAMETER_ROTATION, ++ &ctrl_set_rotate, ++ false + }, + { + V4L2_CID_HFLIP, MMAL_CONTROL_TYPE_STD, + 0, 1, 0, 1, NULL, +- MMAL_PARAMETER_MIRROR, &ctrl_set_flip ++ MMAL_PARAMETER_MIRROR, ++ &ctrl_set_flip, ++ false + }, + { + V4L2_CID_VFLIP, MMAL_CONTROL_TYPE_STD, + 0, 1, 0, 1, NULL, +- MMAL_PARAMETER_MIRROR, &ctrl_set_flip ++ MMAL_PARAMETER_MIRROR, ++ &ctrl_set_flip, ++ false + }, + { + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU, + 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1, + 0, 0, bitrate_mode_qmenu, +- MMAL_PARAMETER_RATECONTROL, &ctrl_set_bitrate_mode ++ MMAL_PARAMETER_RATECONTROL, ++ &ctrl_set_bitrate_mode, ++ false + }, + { + V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD, + 25*1000, 25*1000*1000, 10*1000*1000, 25*1000, NULL, +- MMAL_PARAMETER_VIDEO_BIT_RATE, &ctrl_set_bitrate ++ MMAL_PARAMETER_VIDEO_BIT_RATE, ++ &ctrl_set_bitrate, ++ false + }, + { + V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD, +- 0, 100, ++ 1, 100, + 30, 1, NULL, +- MMAL_PARAMETER_JPEG_Q_FACTOR, &ctrl_set_q_factor ++ MMAL_PARAMETER_JPEG_Q_FACTOR, ++ &ctrl_set_image_encode_output, ++ false ++ }, ++ { ++ V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU, ++ 0, ARRAY_SIZE(mains_freq_qmenu) - 1, ++ 1, 1, NULL, ++ MMAL_PARAMETER_FLICKER_AVOID, ++ &ctrl_set_flicker_avoidance, ++ false ++ }, ++ { ++ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, MMAL_CONTROL_TYPE_STD, ++ 0, 1, ++ 0, 1, NULL, ++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, ++ &ctrl_set_video_encode_param_output, ++ true /* Errors ignored as requires latest firmware to work */ ++ }, ++ { ++ V4L2_CID_MPEG_VIDEO_H264_PROFILE, ++ MMAL_CONTROL_TYPE_STD_MENU, ++ ~((1<exposure_mode_v4l2 == V4L2_EXPOSURE_AUTO || -- dev->exposure_mode_v4l2 == V4L2_EXPOSURE_APERTURE_PRIORITY) && -+ if ((dev->exposure_mode_active != MMAL_PARAM_EXPOSUREMODE_OFF) && - (dev->exp_auto_priority)) { - /* Variable FPS. Define min FPS as 1fps. - * Max as max defined FPS. -@@ -1049,6 +1187,7 @@ int set_framerate_params(struct bm2835_mmal_dev *dev) + for (c = 0; c < V4L2_CTRL_COUNT; c++) { + if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) { + ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c], + &v4l2_ctrls[c]); +- if (ret) ++ if (!v4l2_ctrls[c].ignore_errors && ret) { ++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, ++ "Failed when setting default values for ctrl %d\n", ++ c); + break; ++ } + } + } return ret; - } + ++int set_framerate_params(struct bm2835_mmal_dev *dev) ++{ ++ struct mmal_parameter_fps_range fps_range; ++ int ret; ++ ++ if ((dev->exposure_mode_active != MMAL_PARAM_EXPOSUREMODE_OFF) && ++ (dev->exp_auto_priority)) { ++ /* Variable FPS. Define min FPS as 1fps. ++ * Max as max defined FPS. ++ */ ++ fps_range.fps_low.num = 1; ++ fps_range.fps_low.den = 1; ++ fps_range.fps_high.num = dev->capture.timeperframe.denominator; ++ fps_range.fps_high.den = dev->capture.timeperframe.numerator; ++ } else { ++ /* Fixed FPS - set min and max to be the same */ ++ fps_range.fps_low.num = fps_range.fps_high.num = ++ dev->capture.timeperframe.denominator; ++ fps_range.fps_low.den = fps_range.fps_high.den = ++ dev->capture.timeperframe.numerator; ++ } ++ ++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, ++ "Set fps range to %d/%d to %d/%d\n", ++ fps_range.fps_low.num, ++ fps_range.fps_low.den, ++ fps_range.fps_high.num, ++ fps_range.fps_high.den ++ ); ++ ++ ret = vchiq_mmal_port_parameter_set(dev->instance, ++ &dev->component[MMAL_COMPONENT_CAMERA]-> ++ output[MMAL_CAMERA_PORT_PREVIEW], ++ MMAL_PARAMETER_FPS_RANGE, ++ &fps_range, sizeof(fps_range)); ++ ret += vchiq_mmal_port_parameter_set(dev->instance, ++ &dev->component[MMAL_COMPONENT_CAMERA]-> ++ output[MMAL_CAMERA_PORT_VIDEO], ++ MMAL_PARAMETER_FPS_RANGE, ++ &fps_range, sizeof(fps_range)); ++ ret += vchiq_mmal_port_parameter_set(dev->instance, ++ &dev->component[MMAL_COMPONENT_CAMERA]-> ++ output[MMAL_CAMERA_PORT_CAPTURE], ++ MMAL_PARAMETER_FPS_RANGE, ++ &fps_range, sizeof(fps_range)); ++ if (ret) ++ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev, ++ "Failed to set fps ret %d\n", ++ ret); ++ ++ return ret; ++ ++} + int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev, struct v4l2_ctrl_handler *hdl) { -@@ -1068,10 +1207,30 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev, +@@ -674,10 +1251,30 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev, break; case MMAL_CONTROL_TYPE_STD_MENU: @@ -105974,129 +109358,129 @@ index 45cf790..b7a7e883 100644 case MMAL_CONTROL_TYPE_INT_MENU: dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl, --- -1.9.3 - - -From 9af6ef1e60349927570700b391c6446ab9cee67e Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 25 Mar 2014 11:48:01 +0000 -Subject: [PATCH 074/124] V4L2: Add manual white balance control. - -Adds support for V4L2_CID_RED_BALANCE and -V4L2_CID_BLUE_BALANCE. Only has an effect if -V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE has -V4L2_WHITE_BALANCE_MANUAL selected. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.h | 4 ++- - drivers/media/platform/bcm2835/controls.c | 39 +++++++++++++++++++++++- - drivers/media/platform/bcm2835/mmal-parameters.h | 8 ++++- - 3 files changed, 48 insertions(+), 3 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index f389bea..4ddd687 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.h -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h -@@ -15,7 +15,7 @@ - * core driver device +diff --git a/drivers/media/platform/bcm2835/mmal-common.h b/drivers/media/platform/bcm2835/mmal-common.h +index 602b4a7..076f9a8 100644 +--- a/drivers/media/platform/bcm2835/mmal-common.h ++++ b/drivers/media/platform/bcm2835/mmal-common.h +@@ -26,6 +26,7 @@ + struct mmal_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ ++ int flags; /* v4l2 flags field */ + u32 mmal; + int depth; + u32 mmal_component; /* MMAL component index to be used to encode */ +diff --git a/drivers/media/platform/bcm2835/mmal-encodings.h b/drivers/media/platform/bcm2835/mmal-encodings.h +index 856e80e..024d620 100644 +--- a/drivers/media/platform/bcm2835/mmal-encodings.h ++++ b/drivers/media/platform/bcm2835/mmal-encodings.h +@@ -12,6 +12,8 @@ + * Simon Mellor + * Luke Diamand */ ++#ifndef MMAL_ENCODINGS_H ++#define MMAL_ENCODINGS_H --#define V4L2_CTRL_COUNT 25 /* number of v4l controls */ -+#define V4L2_CTRL_COUNT 27 /* number of v4l controls */ + #define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4') + #define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3') +@@ -27,6 +29,7 @@ + #define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ') + #define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O') + #define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K') ++#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G') - enum { - MMAL_COMPONENT_CAMERA = 0, -@@ -49,6 +49,8 @@ struct bm2835_mmal_dev { - struct mmal_colourfx colourfx; - int hflip; - int vflip; -+ int red_gain; -+ int blue_gain; - enum mmal_parameter_exposuremode exposure_mode_user; - enum v4l2_exposure_auto_type exposure_mode_v4l2_user; - /* active exposure mode may differ if selected via a scene mode */ -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index b7a7e883..9a40bd0 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -491,6 +491,29 @@ static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev, - &u32_value, sizeof(u32_value)); - } - -+static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev, -+ struct v4l2_ctrl *ctrl, -+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -+{ -+ struct vchiq_mmal_port *control; -+ struct mmal_parameter_awbgains gains; + #define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G') + #define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ') +@@ -91,3 +94,34 @@ + #define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1') + /** Implicitly delineated NAL units without emulation prevention */ + #define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ') + -+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control; + -+ if (ctrl->id == V4L2_CID_RED_BALANCE) -+ dev->red_gain = ctrl->val; -+ else if (ctrl->id == V4L2_CID_BLUE_BALANCE) -+ dev->blue_gain = ctrl->val; ++/** \defgroup MmalColorSpace List of pre-defined video color spaces ++ * This defines a list of common color spaces. This list isn't exhaustive and ++ * is only provided as a convenience to avoid clients having to use FourCC ++ * codes directly. However components are allowed to define and use their own ++ * FourCC codes. ++ */ ++/* @{ */ + -+ gains.r_gain.num = dev->red_gain; -+ gains.b_gain.num = dev->blue_gain; -+ gains.r_gain.den = gains.b_gain.den = 1000; ++/** Unknown color space */ ++#define MMAL_COLOR_SPACE_UNKNOWN 0 ++/** ITU-R BT.601-5 [SDTV] */ ++#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1') ++/** ITU-R BT.709-3 [HDTV] */ ++#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9') ++/** JPEG JFIF */ ++#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I') ++/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */ ++#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C') ++/** Society of Motion Picture and Television Engineers 240M (1999) */ ++#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0') ++/** ITU-R BT.470-2 System M */ ++#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M') ++/** ITU-R BT.470-2 System BG */ ++#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G') ++/** JPEG JFIF, but with 16..255 luma */ ++#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6') ++/* @} MmalColorSpace List */ + -+ return vchiq_mmal_port_parameter_set(dev->instance, control, -+ mmal_ctrl->mmal_id, -+ &gains, sizeof(gains)); -+} -+ - static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev, - struct v4l2_ctrl *ctrl, - const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) -@@ -991,12 +1014,26 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - { - V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, - MMAL_CONTROL_TYPE_STD_MENU, -- ~0x3fe, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL, -+ ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL, - MMAL_PARAMETER_AWB_MODE, - &ctrl_set_awb_mode, - false - }, - { -+ V4L2_CID_RED_BALANCE, MMAL_CONTROL_TYPE_STD, -+ 1, 7999, 1000, 1, NULL, -+ MMAL_PARAMETER_CUSTOM_AWB_GAINS, -+ &ctrl_set_awb_gains, -+ false -+ }, -+ { -+ V4L2_CID_BLUE_BALANCE, MMAL_CONTROL_TYPE_STD, -+ 1, 7999, 1000, 1, NULL, -+ MMAL_PARAMETER_CUSTOM_AWB_GAINS, -+ &ctrl_set_awb_gains, -+ false -+ }, -+ { - V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU, - 0, 15, V4L2_COLORFX_NONE, 0, NULL, - MMAL_PARAMETER_IMAGE_EFFECT, ++#endif /* MMAL_ENCODINGS_H */ diff --git a/drivers/media/platform/bcm2835/mmal-parameters.h b/drivers/media/platform/bcm2835/mmal-parameters.h -index ae8fef9..089f949 100644 +index c611b58..aa0fd18 100644 --- a/drivers/media/platform/bcm2835/mmal-parameters.h +++ b/drivers/media/platform/bcm2835/mmal-parameters.h -@@ -161,7 +161,8 @@ enum mmal_parameter_camera_type { +@@ -57,7 +57,8 @@ enum mmal_parameter_common_type { + MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */ + MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */ + MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */ +- MMAL_PARAMETER_SYSTEM_TIME /**< MMAL_PARAMETER_UINT64_T */ ++ MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */ ++ MMAL_PARAMETER_NO_IMAGE_PADDING /**< MMAL_PARAMETER_BOOLEAN_T */ + }; + + /* camera parameters */ +@@ -161,6 +162,13 @@ enum mmal_parameter_camera_type { MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */ MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */ MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_SHUTTER_SPEED /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ + MMAL_PARAMETER_SHUTTER_SPEED, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ + MMAL_PARAMETER_CUSTOM_AWB_GAINS, /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */ ++}; ++ ++struct mmal_parameter_rational { ++ s32 num; /**< Numerator */ ++ s32 den; /**< Denominator */ }; - struct mmal_parameter_rational { -@@ -292,6 +293,11 @@ enum MMAL_PARAM_FLICKERAVOID_T { - MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF + enum mmal_parameter_camera_config_timestamp_mode { +@@ -176,6 +184,14 @@ enum mmal_parameter_camera_config_timestamp_mode { + */ }; ++struct mmal_parameter_fps_range { ++ /**< Low end of the permitted framerate range */ ++ struct mmal_parameter_rational fps_low; ++ /**< High end of the permitted framerate range */ ++ struct mmal_parameter_rational fps_high; ++}; ++ ++ + /* camera configuration parameter */ + struct mmal_parameter_camera_config { + /* Parameters for setting up the image pools */ +@@ -270,6 +286,19 @@ enum mmal_parameter_imagefx { + MMAL_PARAM_IMAGEFX_CARTOON, + }; + ++enum MMAL_PARAM_FLICKERAVOID_T { ++ MMAL_PARAM_FLICKERAVOID_OFF, ++ MMAL_PARAM_FLICKERAVOID_AUTO, ++ MMAL_PARAM_FLICKERAVOID_50HZ, ++ MMAL_PARAM_FLICKERAVOID_60HZ, ++ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF ++}; ++ +struct mmal_parameter_awbgains { + struct mmal_parameter_rational r_gain; /**< Red gain */ + struct mmal_parameter_rational b_gain; /**< Blue gain */ @@ -106105,119 +109489,140 @@ index ae8fef9..089f949 100644 /** Manner of video rate control */ enum mmal_parameter_rate_control_mode { MMAL_VIDEO_RATECONTROL_DEFAULT, --- -1.9.3 - - -From 33d089a06476db239da8cad1acdb10d57649e10c Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 2 Dec 2013 16:57:44 +0000 -Subject: [PATCH 075/124] config: Enable V4L / MMAL driver - ---- - arch/arm/configs/bcmrpi_defconfig | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index bbf3000..058a520 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -693,6 +693,9 @@ CONFIG_DVB_B2C2_FLEXCOP_USB=m - CONFIG_VIDEO_EM28XX=m - CONFIG_VIDEO_EM28XX_ALSA=m - CONFIG_VIDEO_EM28XX_DVB=m -+CONFIG_V4L_PLATFORM_DRIVERS=y -+CONFIG_VIDEO_BCM2835=y -+CONFIG_VIDEO_BCM2835_MMAL=m - CONFIG_RADIO_SI470X=y - CONFIG_USB_SI470X=m - CONFIG_I2C_SI470X=m --- -1.9.3 - - -From 3534687b35fcd0a7bf954b6a5912b7f007ff4d3b Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 076/124] config: Enable CONFIG_MEMCG, but leave it disabled - (due to memory cost). Enable with cgroup_enable=memory. - ---- - arch/arm/configs/bcmrpi_defconfig | 1 + - kernel/cgroup.c | 27 +++++++++++++++++++++++++++ - mm/memcontrol.c | 1 + - 3 files changed, 29 insertions(+) - -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 058a520..5100760 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -18,6 +18,7 @@ CONFIG_CGROUP_FREEZER=y - CONFIG_CGROUP_DEVICE=y - CONFIG_CGROUP_CPUACCT=y - CONFIG_RESOURCE_COUNTERS=y -+CONFIG_MEMCG=y - CONFIG_BLK_CGROUP=y - CONFIG_NAMESPACES=y - CONFIG_SCHED_AUTOGROUP=y -diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index 0c753dd..a18b46e 100644 ---- a/kernel/cgroup.c -+++ b/kernel/cgroup.c -@@ -5252,6 +5252,33 @@ static int __init cgroup_disable(char *str) - } - __setup("cgroup_disable=", cgroup_disable); - -+static int __init cgroup_enable(char *str) -+{ -+ struct cgroup_subsys *ss; -+ char *token; -+ int i; -+ -+ while ((token = strsep(&str, ",")) != NULL) { -+ if (!*token) -+ continue; -+ -+ /* -+ * cgroup_disable, being at boot time, can't know about -+ * module subsystems, so we don't worry about them. -+ */ -+ for_each_builtin_subsys(ss, i) { -+ if (!strcmp(token, ss->name)) { -+ ss->disabled = 0; -+ printk(KERN_INFO "Disabling %s control group" -+ " subsystem\n", ss->name); -+ break; -+ } -+ } -+ } -+ return 1; -+} -+__setup("cgroup_enable=", cgroup_enable); -+ - /** - * css_from_dir - get corresponding css from the dentry of a cgroup dir - * @dentry: directory dentry of interest -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 5b6b003..56de606 100644 ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -7285,6 +7285,7 @@ struct cgroup_subsys mem_cgroup_subsys = { - .bind = mem_cgroup_bind, - .base_cftypes = mem_cgroup_files, - .early_init = 0, -+ .disabled = 1, +@@ -279,6 +308,85 @@ enum mmal_parameter_rate_control_mode { + MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES }; - #ifdef CONFIG_MEMCG_SWAP ++enum mmal_video_profile { ++ MMAL_VIDEO_PROFILE_H263_BASELINE, ++ MMAL_VIDEO_PROFILE_H263_H320CODING, ++ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE, ++ MMAL_VIDEO_PROFILE_H263_ISWV2, ++ MMAL_VIDEO_PROFILE_H263_ISWV3, ++ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION, ++ MMAL_VIDEO_PROFILE_H263_INTERNET, ++ MMAL_VIDEO_PROFILE_H263_INTERLACE, ++ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY, ++ MMAL_VIDEO_PROFILE_MP4V_SIMPLE, ++ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE, ++ MMAL_VIDEO_PROFILE_MP4V_CORE, ++ MMAL_VIDEO_PROFILE_MP4V_MAIN, ++ MMAL_VIDEO_PROFILE_MP4V_NBIT, ++ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE, ++ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE, ++ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA, ++ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED, ++ MMAL_VIDEO_PROFILE_MP4V_HYBRID, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME, ++ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE, ++ MMAL_VIDEO_PROFILE_H264_BASELINE, ++ MMAL_VIDEO_PROFILE_H264_MAIN, ++ MMAL_VIDEO_PROFILE_H264_EXTENDED, ++ MMAL_VIDEO_PROFILE_H264_HIGH, ++ MMAL_VIDEO_PROFILE_H264_HIGH10, ++ MMAL_VIDEO_PROFILE_H264_HIGH422, ++ MMAL_VIDEO_PROFILE_H264_HIGH444, ++ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE, ++ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF ++}; ++ ++enum mmal_video_level { ++ MMAL_VIDEO_LEVEL_H263_10, ++ MMAL_VIDEO_LEVEL_H263_20, ++ MMAL_VIDEO_LEVEL_H263_30, ++ MMAL_VIDEO_LEVEL_H263_40, ++ MMAL_VIDEO_LEVEL_H263_45, ++ MMAL_VIDEO_LEVEL_H263_50, ++ MMAL_VIDEO_LEVEL_H263_60, ++ MMAL_VIDEO_LEVEL_H263_70, ++ MMAL_VIDEO_LEVEL_MP4V_0, ++ MMAL_VIDEO_LEVEL_MP4V_0b, ++ MMAL_VIDEO_LEVEL_MP4V_1, ++ MMAL_VIDEO_LEVEL_MP4V_2, ++ MMAL_VIDEO_LEVEL_MP4V_3, ++ MMAL_VIDEO_LEVEL_MP4V_4, ++ MMAL_VIDEO_LEVEL_MP4V_4a, ++ MMAL_VIDEO_LEVEL_MP4V_5, ++ MMAL_VIDEO_LEVEL_MP4V_6, ++ MMAL_VIDEO_LEVEL_H264_1, ++ MMAL_VIDEO_LEVEL_H264_1b, ++ MMAL_VIDEO_LEVEL_H264_11, ++ MMAL_VIDEO_LEVEL_H264_12, ++ MMAL_VIDEO_LEVEL_H264_13, ++ MMAL_VIDEO_LEVEL_H264_2, ++ MMAL_VIDEO_LEVEL_H264_21, ++ MMAL_VIDEO_LEVEL_H264_22, ++ MMAL_VIDEO_LEVEL_H264_3, ++ MMAL_VIDEO_LEVEL_H264_31, ++ MMAL_VIDEO_LEVEL_H264_32, ++ MMAL_VIDEO_LEVEL_H264_4, ++ MMAL_VIDEO_LEVEL_H264_41, ++ MMAL_VIDEO_LEVEL_H264_42, ++ MMAL_VIDEO_LEVEL_H264_5, ++ MMAL_VIDEO_LEVEL_H264_51, ++ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF ++}; ++ ++struct mmal_parameter_video_profile { ++ enum mmal_video_profile profile; ++ enum mmal_video_level level; ++}; ++ + /* video parameters */ + + enum mmal_parameter_video_type { +@@ -407,7 +515,16 @@ enum mmal_parameter_video_type { + MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER, + + /** @ref MMAL_PARAMETER_BYTES_T */ +- MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3 ++ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3, ++ ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS, ++ ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, ++ ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER + }; + + /** Valid mirror modes */ +diff --git a/drivers/media/platform/bcm2835/mmal-vchiq.c b/drivers/media/platform/bcm2835/mmal-vchiq.c +index a06fb44..76f249e 100644 +--- a/drivers/media/platform/bcm2835/mmal-vchiq.c ++++ b/drivers/media/platform/bcm2835/mmal-vchiq.c +@@ -742,7 +742,7 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, + return ret; + } + +- ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, HZ); ++ ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, 3*HZ); + if (ret <= 0) { + pr_err("error %d waiting for sync completion\n", ret); + if (ret == 0) +@@ -1326,7 +1326,7 @@ static int port_parameter_get(struct vchiq_mmal_instance *instance, + memcpy(value, &rmsg->u.port_parameter_get_reply.value, + rmsg->u.port_parameter_get_reply.size); + +- pr_info("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, ++ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, + ret, port->component->handle, port->handle, parameter_id); + + release_msg: -- 1.9.3 -From 743f60fc5fd01ae200b457cd0516c3bd086a21ba Mon Sep 17 00:00:00 2001 +From 31b6cfc869189aabbaf9e14e3f81a685ce175e33 Mon Sep 17 00:00:00 2001 From: Julian Scheel Date: Wed, 19 Feb 2014 16:06:59 +0100 -Subject: [PATCH 077/124] snd-bcm2835: Add support for spdif/hdmi passthrough +Subject: [PATCH 32/53] snd-bcm2835: Add support for spdif/hdmi passthrough This adds a dedicated subdevice which can be used for passthrough of non-audio formats (ie encoded a52) through the hdmi audio link. In addition to this @@ -106688,10 +110093,10 @@ index 36afee3..8c2fe26 100755 1.9.3 -From 51af3ff80912d24a40f29a0a40861653a7ed38da Mon Sep 17 00:00:00 2001 +From f016071b3e7716c3aec59024153e8f1462d06b27 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 078/124] dmaengine: Add support for BCM2708 +Subject: [PATCH 33/53] dmaengine: Add support for BCM2708 Add support for DMA controller of BCM2708 as used in the Raspberry Pi. Currently it only supports cyclic DMA. @@ -106705,7 +110110,7 @@ Signed-off-by: Florian Meier create mode 100644 drivers/dma/bcm2708-dmaengine.c diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig -index 605b016..edd5842 100644 +index 5c58638..63c226e 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -312,6 +312,12 @@ config DMA_BCM2835 @@ -106722,7 +110127,7 @@ index 605b016..edd5842 100644 tristate "AM33xx CPPI41 DMA support" depends on ARCH_OMAP diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile -index a029d0f4..f4d9516 100644 +index 5150c82..b79ee23 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o @@ -107331,10 +110736,10 @@ index 0000000..b244293 1.9.3 -From ba4a95b47ab0f20cf64b9b64a6a0517133d69753 Mon Sep 17 00:00:00 2001 +From 41eea6063f1e492bd8f7a04a588405c72afede7a Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 079/124] ASoC: Add support for BCM2708 +Subject: [PATCH 34/53] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -108332,10 +111737,10 @@ index 0000000..ebaf3d6 1.9.3 -From 0ba613ac031e7a3dd6a64240e43aa91dd13972ed Mon Sep 17 00:00:00 2001 +From f95159f7151f7727a66d1b873789d0b3e910fc52 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:37:51 +0100 -Subject: [PATCH 080/124] BCM2708: Extend mach header +Subject: [PATCH 35/53] BCM2708: Extend mach header Extend the headers of the mach-bcm2708 in order to support I2S and DMA engine. @@ -108380,10 +111785,10 @@ index 992a630..2e7e1bb 100644 1.9.3 -From 92a98ed7c228487f2bf0ca37a622a42f374b8c8a Mon Sep 17 00:00:00 2001 +From a52ed2ef06b539ad69fe0279d8aedb26804996fc Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 081/124] ASoC: Add support for PCM5102A codec +Subject: [PATCH 36/53] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -108397,20 +111802,20 @@ Signed-off-by: Florian Meier create mode 100644 sound/soc/codecs/pcm5102a.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 983d087a..f0d76ec 100644 +index f0e8401..269c377 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig -@@ -59,6 +59,7 @@ config SND_SOC_ALL_CODECS - select SND_SOC_PCM1681 if I2C - select SND_SOC_PCM1792A if SPI_MASTER +@@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM3008 + select SND_SOC_PCM512x_I2C if I2C + select SND_SOC_PCM512x_SPI if SPI_MASTER + select SND_SOC_PCM5102A select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_SGTL5000 if I2C -@@ -313,6 +314,9 @@ config SND_SOC_PCM1792A - config SND_SOC_PCM3008 - tristate +@@ -390,6 +391,9 @@ config SND_SOC_PCM512x_SPI + select SND_SOC_PCM512x + select REGMAP_SPI +config SND_SOC_PCM5102A + tristate @@ -108419,21 +111824,21 @@ index 983d087a..f0d76ec 100644 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index bc12676..612f414 100644 +index 3c4d275..919b6f6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile -@@ -46,6 +46,7 @@ snd-soc-hdmi-codec-objs := hdmi.o - snd-soc-pcm1681-objs := pcm1681.o - snd-soc-pcm1792a-codec-objs := pcm1792a.o - snd-soc-pcm3008-objs := pcm3008.o +@@ -58,6 +58,7 @@ snd-soc-pcm3008-objs := pcm3008.o + snd-soc-pcm512x-objs := pcm512x.o + snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o + snd-soc-pcm512x-spi-objs := pcm512x-spi.o +snd-soc-pcm5102a-objs := pcm5102a.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-sgtl5000-objs := sgtl5000.o -@@ -179,6 +180,7 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o - obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o - obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o - obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +@@ -209,6 +210,7 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o + obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o + obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o + obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o +obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o @@ -108511,10 +111916,10 @@ index 0000000..126f1e9 1.9.3 -From 90dbb5060d82f019b1095df7f2168c02cd2b990d Mon Sep 17 00:00:00 2001 +From 4d2a15160575aa8cb63d78a46d3229f2ecdfbf98 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 082/124] BCM2708: Add I2S support to board file +Subject: [PATCH 37/53] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -108525,10 +111930,10 @@ Signed-off-by: Florian Meier 1 file changed, 26 insertions(+) diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 2b11e9d..76d7505 100644 +index ef0935f..7cb8a8e 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -620,6 +620,28 @@ static struct platform_device bcm2835_thermal_device = { +@@ -615,6 +615,28 @@ static struct platform_device bcm2835_thermal_device = { .name = "bcm2835_thermal", }; @@ -108557,7 +111962,7 @@ index 2b11e9d..76d7505 100644 int __init bcm_register_device(struct platform_device *pdev) { int ret; -@@ -747,6 +769,10 @@ void __init bcm2708_init(void) +@@ -738,6 +760,10 @@ void __init bcm2708_init(void) bcm_register_device(&bcm2835_hwmon_device); bcm_register_device(&bcm2835_thermal_device); @@ -108572,10 +111977,10 @@ index 2b11e9d..76d7505 100644 1.9.3 -From 2ea8c33a49e2a568f6c651f686acfa020b79a6ca Mon Sep 17 00:00:00 2001 +From b902daf06f4a3d61dbe79cf0ec9b257c85fe9c1d Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 083/124] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 38/53] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -108727,10 +112132,10 @@ index 0000000..4b70b45 1.9.3 -From 2722b08016a3750c56166a2525a2f9a8e40a388a Mon Sep 17 00:00:00 2001 +From 7e6bb6d22c1d5961a4b7d823ca4990577e0ec230 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 084/124] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 39/53] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -108741,10 +112146,10 @@ Signed-off-by: Florian Meier 1 file changed, 19 insertions(+) diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 76d7505..45d0b4f 100644 +index 7cb8a8e..c4dc10e 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -642,6 +642,20 @@ static struct platform_device bcm2708_i2s_device = { +@@ -637,6 +637,20 @@ static struct platform_device bcm2708_i2s_device = { }; #endif @@ -108765,7 +112170,7 @@ index 76d7505..45d0b4f 100644 int __init bcm_register_device(struct platform_device *pdev) { int ret; -@@ -773,6 +787,11 @@ void __init bcm2708_init(void) +@@ -764,6 +778,11 @@ void __init bcm2708_init(void) bcm_register_device(&bcm2708_i2s_device); #endif @@ -108781,10 +112186,10 @@ index 76d7505..45d0b4f 100644 1.9.3 -From 4427330bbd46ab73d2048bcee7baf1b9eef822d5 Mon Sep 17 00:00:00 2001 +From e9fcabbabda87282ff14cd62837b8c5fb7b29673 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 18:55:53 +0100 -Subject: [PATCH 085/124] ASoC: BCM2708: Add 24 bit support +Subject: [PATCH 40/53] ASoC: BCM2708: Add 24 bit support This adds 24 bit support to the I2S driver of the BCM2708. Besides enabling the 24 bit flags, it includes two bug fixes: @@ -108859,10 +112264,10 @@ index ebaf3d6..a179216 100644 1.9.3 -From ac66718cbff656a673f723425f121bc4b0c1bb22 Mon Sep 17 00:00:00 2001 +From 5fe237762874b2971c5bf8fa9711cd7fd29b7be1 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 2 Dec 2013 20:28:22 +0100 -Subject: [PATCH 086/124] BCM2708: Add I2S and DMA support to default config +Subject: [PATCH 41/53] BCM2708: Add I2S and DMA support to default config This commit adds several modules that are needed for I2S support for the Raspberry Pi to the defconfig. @@ -108873,7 +112278,7 @@ Signed-off-by: Florian Meier 1 file changed, 11 insertions(+) diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 5100760..cde1233 100644 +index d70da44..36e7473 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -739,6 +739,13 @@ CONFIG_SND_USB_UA101=m @@ -108890,7 +112295,7 @@ index 5100760..cde1233 100644 CONFIG_SOUND_PRIME=m CONFIG_HIDRAW=y CONFIG_HID_A4TECH=m -@@ -926,6 +933,10 @@ CONFIG_RTC_DRV_RS5C348=m +@@ -929,6 +936,10 @@ CONFIG_RTC_DRV_RS5C348=m CONFIG_RTC_DRV_DS3234=m CONFIG_RTC_DRV_PCF2123=m CONFIG_RTC_DRV_RX4581=m @@ -108905,10 +112310,10 @@ index 5100760..cde1233 100644 1.9.3 -From 6271fd8699c1c15df1495540d730cc26454aadfe Mon Sep 17 00:00:00 2001 +From 13502daa009c7970b41202cc34c6e3d757476c47 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 087/124] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 42/53] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -108927,7 +112332,7 @@ Signed-off-by: Florian Meier create mode 100644 sound/soc/codecs/pcm1794a.c diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index cde1233..b1536f2 100644 +index 36e7473..f877ab2 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -744,8 +744,10 @@ CONFIG_SND_SOC_DMAENGINE_PCM=y @@ -108942,10 +112347,10 @@ index cde1233..b1536f2 100644 CONFIG_HIDRAW=y CONFIG_HID_A4TECH=m diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 45d0b4f..b5e4272 100644 +index c4dc10e..f2b3990 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -656,6 +656,20 @@ static struct platform_device snd_pcm5102a_codec_device = { +@@ -651,6 +651,20 @@ static struct platform_device snd_pcm5102a_codec_device = { }; #endif @@ -108966,7 +112371,7 @@ index 45d0b4f..b5e4272 100644 int __init bcm_register_device(struct platform_device *pdev) { int ret; -@@ -792,6 +806,11 @@ void __init bcm2708_init(void) +@@ -783,6 +797,11 @@ void __init bcm2708_init(void) bcm_register_device(&snd_pcm5102a_codec_device); #endif @@ -109109,20 +112514,20 @@ index 0000000..ef3cd93 +MODULE_DESCRIPTION("ASoC Driver for RPi-DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index f0d76ec..4d2569e 100644 +index 269c377..54dec92 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig -@@ -59,6 +59,7 @@ config SND_SOC_ALL_CODECS - select SND_SOC_PCM1681 if I2C - select SND_SOC_PCM1792A if SPI_MASTER +@@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM3008 + select SND_SOC_PCM512x_I2C if I2C + select SND_SOC_PCM512x_SPI if SPI_MASTER + select SND_SOC_PCM1794A select SND_SOC_PCM5102A select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C -@@ -314,6 +315,9 @@ config SND_SOC_PCM1792A - config SND_SOC_PCM3008 - tristate +@@ -391,6 +392,9 @@ config SND_SOC_PCM512x_SPI + select SND_SOC_PCM512x + select REGMAP_SPI +config SND_SOC_PCM1794A + tristate @@ -109131,21 +112536,21 @@ index f0d76ec..4d2569e 100644 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 612f414..9b806a2 100644 +index 919b6f6..7f0eefa 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile -@@ -46,6 +46,7 @@ snd-soc-hdmi-codec-objs := hdmi.o - snd-soc-pcm1681-objs := pcm1681.o - snd-soc-pcm1792a-codec-objs := pcm1792a.o - snd-soc-pcm3008-objs := pcm3008.o +@@ -58,6 +58,7 @@ snd-soc-pcm3008-objs := pcm3008.o + snd-soc-pcm512x-objs := pcm512x.o + snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o + snd-soc-pcm512x-spi-objs := pcm512x-spi.o +snd-soc-pcm1794a-objs := pcm1794a.o snd-soc-pcm5102a-objs := pcm5102a.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o -@@ -180,6 +181,7 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o - obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o - obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o - obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +@@ -210,6 +211,7 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o + obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o + obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o + obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o +obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o @@ -109222,13 +112627,13 @@ index 0000000..b4eaa44 1.9.3 -From 30393a2527f1ee38643217abc66a84da45288c8f Mon Sep 17 00:00:00 2001 +From bb796a84fb72f20b97008b62766aba9b0f1f0aa2 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 088/124] ASoC: wm8804: Implement MCLK configuration options, - add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs - for most sample rates. At 192kHz only 128xfs is supported. The existing - driver selects 128xfs automatically for some lower samples rates. By using an +Subject: [PATCH 43/53] ASoC: wm8804: Implement MCLK configuration options, add + 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs for + most sample rates. At 192kHz only 128xfs is supported. The existing driver + selects 128xfs automatically for some lower samples rates. By using an additional mclk_div divider, it is now possible to control the behaviour. This allows using 256xfs PLL frequency on all sample rates up to 96kHz. It should allow lower jitter and better signal quality. The behavior has to be @@ -109245,7 +112650,7 @@ Signed-off-by: Daniel Matuschek 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c -index 9bc8206..c35b4f3 100644 +index ee76f0f..d8923c1 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -63,6 +63,7 @@ struct wm8804_priv { @@ -109315,7 +112720,7 @@ index 9bc8206..c35b4f3 100644 default: dev_err(dai->dev, "Unknown clock divider: %d\n", div_id); return -EINVAL; -@@ -641,7 +652,7 @@ static const struct snd_soc_dai_ops wm8804_dai_ops = { +@@ -633,7 +644,7 @@ static const struct snd_soc_dai_ops wm8804_dai_ops = { }; #define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ @@ -109342,10 +112747,10 @@ index 8ec14f5..e72d4f4 100644 1.9.3 -From 448636fb05d5f5641647dd8914bd4ad44be9843e Mon Sep 17 00:00:00 2001 +From 72a1c736563d1d7696cfef21fae4f6cdcccb7539 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 089/124] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 44/53] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -109551,10 +112956,10 @@ index 0000000..e4f769d 1.9.3 -From bc390b2f67083659c698c812853bbfc8da92684f Mon Sep 17 00:00:00 2001 +From 09323a6e350b335de392864e3d299305f74ac904 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 090/124] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 45/53] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -109563,10 +112968,10 @@ Signed-off-by: Daniel Matuschek 1 file changed, 20 insertions(+) diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index b5e4272..d7055e1 100644 +index f2b3990..f5afd86 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -656,6 +656,21 @@ static struct platform_device snd_pcm5102a_codec_device = { +@@ -651,6 +651,21 @@ static struct platform_device snd_pcm5102a_codec_device = { }; #endif @@ -109588,7 +112993,7 @@ index b5e4272..d7055e1 100644 #if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE) static struct platform_device snd_rpi_dac_device = { .name = "snd-rpi-dac", -@@ -806,6 +821,11 @@ void __init bcm2708_init(void) +@@ -797,6 +812,11 @@ void __init bcm2708_init(void) bcm_register_device(&snd_pcm5102a_codec_device); #endif @@ -109604,10 +113009,10 @@ index b5e4272..d7055e1 100644 1.9.3 -From 5d1bdb6a40cecb80a6f833357404767d4c49fb50 Mon Sep 17 00:00:00 2001 +From caa3a5c3dd0948bdb22f5e5d584a7a90ddb7c809 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:27:28 +0100 -Subject: [PATCH 091/124] BCM2708: Added HiFiBerry Digi configuration option It +Subject: [PATCH 46/53] BCM2708: Added HiFiBerry Digi configuration option It will be compiled as a module by default. This also includes the WM8804 driver. @@ -109617,7 +113022,7 @@ Signed-off-by: Daniel Matuschek 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index b1536f2..b2b9def 100644 +index f877ab2..3d3c8ab 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -742,8 +742,10 @@ CONFIG_SND_USB_6FIRE=m @@ -109635,11 +113040,11 @@ index b1536f2..b2b9def 100644 1.9.3 -From 48a90b6f530abe16614131e71fc8384f3f5ab007 Mon Sep 17 00:00:00 2001 +From 43fa6b1607d23abfb38f1df99c402a2c33818d2b Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 092/124] ASoC: wm8804: Set idle_bias_off to false Idle bias - has been change to remove warning on driver startup +Subject: [PATCH 47/53] ASoC: wm8804: Set idle_bias_off to false Idle bias has + been change to remove warning on driver startup Signed-off-by: Daniel Matuschek --- @@ -109647,10 +113052,10 @@ Signed-off-by: Daniel Matuschek 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c -index c35b4f3..8915d08 100644 +index d8923c1..2787042 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c -@@ -685,7 +685,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { +@@ -677,7 +677,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .suspend = wm8804_suspend, .resume = wm8804_resume, .set_bias_level = wm8804_set_bias_level, @@ -109663,10 +113068,10 @@ index c35b4f3..8915d08 100644 1.9.3 -From 475e12cf93f019d8c28aedba70e38201bc4aabe4 Mon Sep 17 00:00:00 2001 +From 34eb11fc484998a647a7d01ca3fe86dbc4815d8e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 12 Mar 2014 11:46:34 +0000 -Subject: [PATCH 093/124] ASoc: Don't report S24_LE support, it produces white +Subject: [PATCH 48/53] ASoc: Don't report S24_LE support, it produces white noise with xbmc --- @@ -109704,28 +113109,26 @@ index 126f1e9..7812d34 100644 1.9.3 -From 5adb33ff9c1f0ceb9c2d8a904e35e62f0681f2b8 Mon Sep 17 00:00:00 2001 +From fad6180821496768e424233db1996980cb06f8ff Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 094/124] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 49/53] Add IQaudIO Sound Card support for Raspberry Pi --- arch/arm/configs/bcmrpi_defconfig | 1 + - arch/arm/mach-bcm2708/bcm2708.c | 22 ++ - sound/soc/bcm/Kconfig | 7 + + arch/arm/mach-bcm2708/bcm2708.c | 22 ++++ + sound/soc/bcm/Kconfig | 7 ++ sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/iqaudio-dac.c | 111 +++++++ + sound/soc/bcm/iqaudio-dac.c | 111 +++++++++++++++++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + - sound/soc/codecs/pcm512x.c | 677 ++++++++++++++++++++++++++++++++++++++ - sound/soc/codecs/pcm512x.h | 142 ++++++++ - 9 files changed, 968 insertions(+) + sound/soc/codecs/pcm512x.c | 243 ++++++++++++++++++++++++++------------ + sound/soc/codecs/pcm512x.h | 143 +++++++++------------- + 9 files changed, 372 insertions(+), 163 deletions(-) create mode 100644 sound/soc/bcm/iqaudio-dac.c - create mode 100644 sound/soc/codecs/pcm512x.c - create mode 100644 sound/soc/codecs/pcm512x.h diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index b2b9def..f0a5370 100644 +index 3d3c8ab..a024670 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -750,6 +750,7 @@ CONFIG_SND_BCM2708_SOC_RPI_DAC=m @@ -109737,10 +113140,10 @@ index b2b9def..f0a5370 100644 CONFIG_HIDRAW=y CONFIG_HID_A4TECH=m diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index d7055e1..c6f04df 100644 +index f5afd86..b0aec82 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -685,6 +685,22 @@ static struct platform_device snd_pcm1794a_codec_device = { +@@ -680,6 +680,22 @@ static struct platform_device snd_pcm1794a_codec_device = { }; #endif @@ -109763,7 +113166,7 @@ index d7055e1..c6f04df 100644 int __init bcm_register_device(struct platform_device *pdev) { int ret; -@@ -831,6 +847,12 @@ void __init bcm2708_init(void) +@@ -822,6 +838,12 @@ void __init bcm2708_init(void) bcm_register_device(&snd_pcm1794a_codec_device); #endif @@ -109923,18 +113326,18 @@ index 0000000..515f044 +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 4d2569e..ac28805 100644 +index 54dec92..b3a0488 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig -@@ -61,6 +61,7 @@ config SND_SOC_ALL_CODECS - select SND_SOC_PCM3008 +@@ -71,6 +71,7 @@ config SND_SOC_ALL_CODECS + select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_PCM1794A select SND_SOC_PCM5102A + select SND_SOC_PCM512x if SND_SOC_I2C_AND_SPI select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_SGTL5000 if I2C -@@ -321,6 +322,9 @@ config SND_SOC_PCM1794A +@@ -398,6 +399,9 @@ config SND_SOC_PCM1794A config SND_SOC_PCM5102A tristate @@ -109945,19 +113348,19 @@ index 4d2569e..ac28805 100644 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 9b806a2..61461c1 100644 +index 7f0eefa..95600ec 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile -@@ -48,6 +48,7 @@ snd-soc-pcm1792a-codec-objs := pcm1792a.o - snd-soc-pcm3008-objs := pcm3008.o +@@ -60,6 +60,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o + snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-pcm1794a-objs := pcm1794a.o snd-soc-pcm5102a-objs := pcm5102a.o +snd-soc-pcm512x-objs := pcm512x.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-sgtl5000-objs := sgtl5000.o -@@ -183,6 +184,7 @@ obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o - obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +@@ -213,6 +214,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o + obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o +obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o @@ -109965,79 +113368,57 @@ index 9b806a2..61461c1 100644 obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c -new file mode 100644 -index 0000000..55b6200 ---- /dev/null +index 4b4c0c7..b669e15 100644 +--- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c -@@ -0,0 +1,677 @@ -+/* -+ * Driver for the PCM512x CODECs -+ * -+ * Author: Mark Brown -+ * Copyright 2014 Linaro Ltd -+ * -+ * 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. -+ */ -+ -+ -+#include -+#include -+#include +@@ -18,9 +18,11 @@ + #include + #include + #include +#include -+#include -+#include -+#include + #include + #include + #include +#include -+#include -+#include -+#include -+ -+#include "pcm512x.h" -+ -+#define PCM512x_NUM_SUPPLIES 3 + #include + #include + #include +@@ -28,7 +30,7 @@ + #include "pcm512x.h" + + #define PCM512x_NUM_SUPPLIES 3 +-static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { +static const char *pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { -+ "AVDD", -+ "DVDD", -+ "CPVDD", -+}; -+ -+struct pcm512x_priv { -+ struct regmap *regmap; -+ struct clk *sclk; -+ struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; -+ struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; -+}; -+ -+/* -+ * We can't use the same notifier block for more than one supply and -+ * there's no way I can see to get from a callback to the caller -+ * except container_of(). -+ */ -+#define PCM512x_REGULATOR_EVENT(n) \ -+static int pcm512x_regulator_event_##n(struct notifier_block *nb, \ -+ unsigned long event, void *data) \ -+{ \ -+ struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \ -+ supply_nb[n]); \ -+ if (event & REGULATOR_EVENT_DISABLE) { \ -+ regcache_mark_dirty(pcm512x->regmap); \ -+ regcache_cache_only(pcm512x->regmap, true); \ -+ } \ -+ return 0; \ -+} -+ -+PCM512x_REGULATOR_EVENT(0) -+PCM512x_REGULATOR_EVENT(1) -+PCM512x_REGULATOR_EVENT(2) -+ -+static const struct reg_default pcm512x_reg_defaults[] = { + "AVDD", + "DVDD", + "CPVDD", +@@ -64,29 +66,22 @@ PCM512x_REGULATOR_EVENT(1) + PCM512x_REGULATOR_EVENT(2) + + static const struct reg_default pcm512x_reg_defaults[] = { +- { PCM512x_RESET, 0x00 }, +- { PCM512x_POWER, 0x00 }, +- { PCM512x_MUTE, 0x00 }, +- { PCM512x_DSP, 0x00 }, +- { PCM512x_PLL_REF, 0x00 }, +- { PCM512x_DAC_ROUTING, 0x11 }, +- { PCM512x_DSP_PROGRAM, 0x01 }, +- { PCM512x_CLKDET, 0x00 }, +- { PCM512x_AUTO_MUTE, 0x00 }, +- { PCM512x_ERROR_DETECT, 0x00 }, +- { PCM512x_DIGITAL_VOLUME_1, 0x00 }, +- { PCM512x_DIGITAL_VOLUME_2, 0x30 }, +- { PCM512x_DIGITAL_VOLUME_3, 0x30 }, +- { PCM512x_DIGITAL_MUTE_1, 0x22 }, +- { PCM512x_DIGITAL_MUTE_2, 0x00 }, +- { PCM512x_DIGITAL_MUTE_3, 0x07 }, +- { PCM512x_OUTPUT_AMPLITUDE, 0x00 }, +- { PCM512x_ANALOG_GAIN_CTRL, 0x00 }, +- { PCM512x_UNDERVOLTAGE_PROT, 0x00 }, +- { PCM512x_ANALOG_MUTE_CTRL, 0x00 }, +- { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, +- { PCM512x_VCOM_CTRL_1, 0x00 }, +- { PCM512x_VCOM_CTRL_2, 0x01 }, + { PCM512x_RESET, 0x00 }, + { PCM512x_POWER, 0x00 }, + { PCM512x_MUTE, 0x00 }, @@ -110054,279 +113435,153 @@ index 0000000..55b6200 + { PCM512x_DIGITAL_MUTE_1, 0x22 }, + { PCM512x_DIGITAL_MUTE_2, 0x00 }, + { PCM512x_DIGITAL_MUTE_3, 0x07 }, -+}; -+ -+static bool pcm512x_readable(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case PCM512x_RESET: -+ case PCM512x_POWER: -+ case PCM512x_MUTE: -+ case PCM512x_PLL_EN: -+ case PCM512x_SPI_MISO_FUNCTION: -+ case PCM512x_DSP: -+ case PCM512x_GPIO_EN: -+ case PCM512x_BCLK_LRCLK_CFG: -+ case PCM512x_DSP_GPIO_INPUT: -+ case PCM512x_MASTER_MODE: -+ case PCM512x_PLL_REF: -+ case PCM512x_PLL_COEFF_0: -+ case PCM512x_PLL_COEFF_1: -+ case PCM512x_PLL_COEFF_2: -+ case PCM512x_PLL_COEFF_3: -+ case PCM512x_PLL_COEFF_4: -+ case PCM512x_DSP_CLKDIV: -+ case PCM512x_DAC_CLKDIV: -+ case PCM512x_NCP_CLKDIV: -+ case PCM512x_OSR_CLKDIV: -+ case PCM512x_MASTER_CLKDIV_1: -+ case PCM512x_MASTER_CLKDIV_2: -+ case PCM512x_FS_SPEED_MODE: -+ case PCM512x_IDAC_1: -+ case PCM512x_IDAC_2: -+ case PCM512x_ERROR_DETECT: -+ case PCM512x_I2S_1: -+ case PCM512x_I2S_2: -+ case PCM512x_DAC_ROUTING: -+ case PCM512x_DSP_PROGRAM: -+ case PCM512x_CLKDET: -+ case PCM512x_AUTO_MUTE: -+ case PCM512x_DIGITAL_VOLUME_1: -+ case PCM512x_DIGITAL_VOLUME_2: -+ case PCM512x_DIGITAL_VOLUME_3: -+ case PCM512x_DIGITAL_MUTE_1: -+ case PCM512x_DIGITAL_MUTE_2: -+ case PCM512x_DIGITAL_MUTE_3: -+ case PCM512x_GPIO_OUTPUT_1: -+ case PCM512x_GPIO_OUTPUT_2: -+ case PCM512x_GPIO_OUTPUT_3: -+ case PCM512x_GPIO_OUTPUT_4: -+ case PCM512x_GPIO_OUTPUT_5: -+ case PCM512x_GPIO_OUTPUT_6: -+ case PCM512x_GPIO_CONTROL_1: -+ case PCM512x_GPIO_CONTROL_2: -+ case PCM512x_OVERFLOW: -+ case PCM512x_RATE_DET_1: -+ case PCM512x_RATE_DET_2: -+ case PCM512x_RATE_DET_3: -+ case PCM512x_RATE_DET_4: -+ case PCM512x_ANALOG_MUTE_DET: -+ case PCM512x_GPIN: -+ case PCM512x_DIGITAL_MUTE_DET: -+ return true; -+ default: + }; + + static bool pcm512x_readable(struct device *dev, unsigned int reg) +@@ -146,18 +141,9 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg) + case PCM512x_ANALOG_MUTE_DET: + case PCM512x_GPIN: + case PCM512x_DIGITAL_MUTE_DET: +- case PCM512x_OUTPUT_AMPLITUDE: +- case PCM512x_ANALOG_GAIN_CTRL: +- case PCM512x_UNDERVOLTAGE_PROT: +- case PCM512x_ANALOG_MUTE_CTRL: +- case PCM512x_ANALOG_GAIN_BOOST: +- case PCM512x_VCOM_CTRL_1: +- case PCM512x_VCOM_CTRL_2: +- case PCM512x_CRAM_CTRL: + return true; + default: +- /* There are 256 raw register addresses */ +- return reg < 0xff; + return false; -+ } -+} -+ -+static bool pcm512x_volatile(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case PCM512x_PLL_EN: -+ case PCM512x_OVERFLOW: -+ case PCM512x_RATE_DET_1: -+ case PCM512x_RATE_DET_2: -+ case PCM512x_RATE_DET_3: -+ case PCM512x_RATE_DET_4: -+ case PCM512x_ANALOG_MUTE_DET: -+ case PCM512x_GPIN: -+ case PCM512x_DIGITAL_MUTE_DET: -+ return true; -+ default: + } + } + +@@ -173,22 +159,17 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg) + case PCM512x_ANALOG_MUTE_DET: + case PCM512x_GPIN: + case PCM512x_DIGITAL_MUTE_DET: +- case PCM512x_CRAM_CTRL: + return true; + default: +- /* There are 256 raw register addresses */ +- return reg < 0xff; + return false; -+ } -+} -+ -+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); -+ + } + } + + static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); +-static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); +-static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); + +-static const char * const pcm512x_dsp_program_texts[] = { +static const char *pcm512x_dsp_program_texts[] = { -+ "FIR interpolation with de-emphasis", -+ "Low latency IIR with de-emphasis", -+ "High attenuation with de-emphasis", -+ "Ringing-less low latency FIR", -+}; -+ -+static const unsigned int pcm512x_dsp_program_values[] = { -+ 1, -+ 2, -+ 3, -+ 5, -+ 7, -+}; -+ + "FIR interpolation with de-emphasis", + "Low latency IIR with de-emphasis", +- "Fixed process flow", + "High attenuation with de-emphasis", + "Ringing-less low latency FIR", + }; +@@ -201,31 +182,31 @@ static const unsigned int pcm512x_dsp_program_values[] = { + 7, + }; + +-static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, +- PCM512x_DSP_PROGRAM, 0, 0x1f, +- pcm512x_dsp_program_texts, +- pcm512x_dsp_program_values); +static const SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, + PCM512x_DSP_PROGRAM, 0, 0x1f, + pcm512x_dsp_program_texts, + pcm512x_dsp_program_values); -+ + +-static const char * const pcm512x_clk_missing_text[] = { +static const char *pcm512x_clk_missing_text[] = { -+ "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" -+}; -+ -+static const struct soc_enum pcm512x_clk_missing = + "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" + }; + + static const struct soc_enum pcm512x_clk_missing = +- SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 8, pcm512x_clk_missing_text); + SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 7, pcm512x_clk_missing_text); -+ + +-static const char * const pcm512x_autom_text[] = { +static const char *pcm512x_autom_text[] = { -+ "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" -+}; -+ -+static const struct soc_enum pcm512x_autom_l = + "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" + }; + + static const struct soc_enum pcm512x_autom_l = +- SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8, + SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 7, -+ pcm512x_autom_text); -+ -+static const struct soc_enum pcm512x_autom_r = + pcm512x_autom_text); + + static const struct soc_enum pcm512x_autom_r = +- SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, + SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 7, -+ pcm512x_autom_text); -+ + pcm512x_autom_text); + +-static const char * const pcm512x_ramp_rate_text[] = { +static const char *pcm512x_ramp_rate_text[] = { -+ "1 sample/update", "2 samples/update", "4 samples/update", -+ "Immediate" -+}; -+ -+static const struct soc_enum pcm512x_vndf = -+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4, -+ pcm512x_ramp_rate_text); -+ -+static const struct soc_enum pcm512x_vnuf = -+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4, -+ pcm512x_ramp_rate_text); -+ -+static const struct soc_enum pcm512x_vedf = -+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, -+ pcm512x_ramp_rate_text); -+ + "1 sample/update", "2 samples/update", "4 samples/update", + "Immediate" + }; +@@ -242,7 +223,7 @@ static const struct soc_enum pcm512x_vedf = + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, + pcm512x_ramp_rate_text); + +-static const char * const pcm512x_ramp_step_text[] = { +static const char *pcm512x_ramp_step_text[] = { -+ "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" -+}; -+ -+static const struct soc_enum pcm512x_vnds = -+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4, -+ pcm512x_ramp_step_text); -+ -+static const struct soc_enum pcm512x_vnus = -+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4, -+ pcm512x_ramp_step_text); -+ -+static const struct soc_enum pcm512x_veds = -+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, -+ pcm512x_ramp_step_text); -+ -+static const struct snd_kcontrol_new pcm512x_controls[] = { -+SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, -+ PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), -+SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, -+ PCM512x_RQMR_SHIFT, 1, 1), -+ -+SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), -+SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program), -+ -+SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), -+SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), -+SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), -+SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, -+ PCM512x_ACTL_SHIFT, 1, 0), -+SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, -+ PCM512x_AMLR_SHIFT, 1, 0), -+ -+SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), -+SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), -+SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), -+SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), -+SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), -+SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), -+}; -+ -+static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { -+SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), -+SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), -+ -+SND_SOC_DAPM_OUTPUT("OUTL"), -+SND_SOC_DAPM_OUTPUT("OUTR"), -+}; -+ -+static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { -+ { "DACL", NULL, "Playback" }, -+ { "DACR", NULL, "Playback" }, -+ -+ { "OUTL", NULL, "DACL" }, -+ { "OUTR", NULL, "DACR" }, -+}; -+ -+static int pcm512x_set_bias_level(struct snd_soc_codec *codec, -+ enum snd_soc_bias_level level) -+{ -+ struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev); -+ int ret; -+ -+ switch (level) { -+ case SND_SOC_BIAS_ON: -+ case SND_SOC_BIAS_PREPARE: -+ break; -+ -+ case SND_SOC_BIAS_STANDBY: -+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, -+ PCM512x_RQST, 0); -+ if (ret != 0) { -+ dev_err(codec->dev, "Failed to remove standby: %d\n", -+ ret); -+ return ret; -+ } -+ break; -+ -+ case SND_SOC_BIAS_OFF: -+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, -+ PCM512x_RQST, PCM512x_RQST); -+ if (ret != 0) { -+ dev_err(codec->dev, "Failed to request standby: %d\n", -+ ret); -+ return ret; -+ } -+ break; -+ } -+ -+ codec->dapm.bias_level = level; -+ -+ return 0; -+} -+ -+static struct snd_soc_dai_driver pcm512x_dai = { -+ .name = "pcm512x-hifi", -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_192000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE -+ }, -+}; -+ -+static struct snd_soc_codec_driver pcm512x_codec_driver = { -+ .set_bias_level = pcm512x_set_bias_level, -+ .idle_bias_off = true, -+ -+ .controls = pcm512x_controls, -+ .num_controls = ARRAY_SIZE(pcm512x_controls), -+ .dapm_widgets = pcm512x_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), -+ .dapm_routes = pcm512x_dapm_routes, -+ .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), -+}; -+ + "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" + }; + +@@ -258,13 +239,10 @@ static const struct soc_enum pcm512x_veds = + SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, + pcm512x_ramp_step_text); + ++/* Don't let the DAC go into clipping by limiting the alsa volume control range */ + static const struct snd_kcontrol_new pcm512x_controls[] = { +-SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, +- PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), +-SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, +- PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), +-SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, +- PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), ++SOC_DOUBLE_R_RANGE_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, ++ PCM512x_DIGITAL_VOLUME_3, 0, 40, 255, 1, digital_tlv), + SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, + PCM512x_RQMR_SHIFT, 1, 1), + +@@ -365,32 +343,27 @@ static struct snd_soc_codec_driver pcm512x_codec_driver = { + .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), + }; + +-static const struct regmap_range_cfg pcm512x_range = { +- .name = "Pages", .range_min = PCM512x_VIRT_BASE, +- .range_max = PCM512x_MAX_REGISTER, +- .selector_reg = PCM512x_PAGE, +- .selector_mask = 0xff, +- .window_start = 0, .window_len = 0x100, +-}; +- +-const struct regmap_config pcm512x_regmap = { +static const struct regmap_config pcm512x_regmap = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ -+ .readable_reg = pcm512x_readable, -+ .volatile_reg = pcm512x_volatile, -+ -+ .max_register = PCM512x_MAX_REGISTER, -+ .reg_defaults = pcm512x_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), -+ .cache_type = REGCACHE_RBTREE, -+}; -+ + .reg_bits = 8, + .val_bits = 8, + + .readable_reg = pcm512x_readable, + .volatile_reg = pcm512x_volatile, + +- .ranges = &pcm512x_range, +- .num_ranges = 1, +- + .max_register = PCM512x_MAX_REGISTER, + .reg_defaults = pcm512x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), + .cache_type = REGCACHE_RBTREE, + }; +-EXPORT_SYMBOL_GPL(pcm512x_regmap); + +-int pcm512x_probe(struct device *dev, struct regmap *regmap) +static const struct of_device_id pcm512x_of_match[] = { + { .compatible = "ti,pcm5121", }, + { .compatible = "ti,pcm5122", }, @@ -110335,201 +113590,51 @@ index 0000000..55b6200 +MODULE_DEVICE_TABLE(of, pcm512x_of_match); + +static int pcm512x_probe(struct device *dev, struct regmap *regmap) -+{ -+ struct pcm512x_priv *pcm512x; -+ int i, ret; -+ -+ pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL); -+ if (!pcm512x) -+ return -ENOMEM; -+ -+ dev_set_drvdata(dev, pcm512x); -+ pcm512x->regmap = regmap; -+ -+ for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) -+ pcm512x->supplies[i].supply = pcm512x_supply_names[i]; -+ -+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies), -+ pcm512x->supplies); -+ if (ret != 0) { -+ dev_err(dev, "Failed to get supplies: %d\n", ret); -+ return ret; -+ } -+ -+ pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0; -+ pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1; -+ pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; -+ -+ for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { -+ ret = regulator_register_notifier(pcm512x->supplies[i].consumer, -+ &pcm512x->supply_nb[i]); -+ if (ret != 0) { -+ dev_err(dev, -+ "Failed to register regulator notifier: %d\n", -+ ret); -+ } -+ } -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), -+ pcm512x->supplies); -+ if (ret != 0) { -+ dev_err(dev, "Failed to enable supplies: %d\n", ret); -+ return ret; -+ } -+ -+ /* Reset the device, verifying I/O in the process for I2C */ -+ ret = regmap_write(regmap, PCM512x_RESET, -+ PCM512x_RSTM | PCM512x_RSTR); -+ if (ret != 0) { -+ dev_err(dev, "Failed to reset device: %d\n", ret); -+ goto err; -+ } -+ -+ ret = regmap_write(regmap, PCM512x_RESET, 0); -+ if (ret != 0) { -+ dev_err(dev, "Failed to reset device: %d\n", ret); -+ goto err; -+ } -+ -+ pcm512x->sclk = devm_clk_get(dev, NULL); -+ if (IS_ERR(pcm512x->sclk)) { -+ if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ -+ dev_info(dev, "No SCLK, using BCLK: %ld\n", -+ PTR_ERR(pcm512x->sclk)); -+ -+ /* Disable reporting of missing SCLK as an error */ -+ regmap_update_bits(regmap, PCM512x_ERROR_DETECT, -+ PCM512x_IDCH, PCM512x_IDCH); -+ -+ /* Switch PLL input to BCLK */ -+ regmap_update_bits(regmap, PCM512x_PLL_REF, -+ PCM512x_SREF, PCM512x_SREF); -+ } else { -+ ret = clk_prepare_enable(pcm512x->sclk); -+ if (ret != 0) { -+ dev_err(dev, "Failed to enable SCLK: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ /* Default to standby mode */ -+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, -+ PCM512x_RQST, PCM512x_RQST); -+ if (ret != 0) { -+ dev_err(dev, "Failed to request standby: %d\n", -+ ret); -+ goto err_clk; -+ } -+ -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ pm_runtime_idle(dev); -+ -+ ret = snd_soc_register_codec(dev, &pcm512x_codec_driver, -+ &pcm512x_dai, 1); -+ if (ret != 0) { -+ dev_err(dev, "Failed to register CODEC: %d\n", ret); -+ goto err_pm; -+ } -+ + { + struct pcm512x_priv *pcm512x; + int i, ret; +@@ -490,6 +463,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) + goto err_pm; + } + + dev_info(dev, "Completed initialisation - pcm512x_probe"); + -+ return 0; -+ -+err_pm: -+ pm_runtime_disable(dev); -+err_clk: -+ if (!IS_ERR(pcm512x->sclk)) -+ clk_disable_unprepare(pcm512x->sclk); -+err: -+ regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), -+ pcm512x->supplies); -+ return ret; -+} -+ + return 0; + + err_pm: +@@ -502,9 +477,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) + pcm512x->supplies); + return ret; + } +-EXPORT_SYMBOL_GPL(pcm512x_probe); + +-void pcm512x_remove(struct device *dev) +static void pcm512x_remove(struct device *dev) -+{ -+ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); -+ -+ snd_soc_unregister_codec(dev); -+ pm_runtime_disable(dev); -+ if (!IS_ERR(pcm512x->sclk)) -+ clk_disable_unprepare(pcm512x->sclk); -+ regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), -+ pcm512x->supplies); -+} -+ + { + struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); + +@@ -515,8 +489,8 @@ void pcm512x_remove(struct device *dev) + regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), + pcm512x->supplies); + } +-EXPORT_SYMBOL_GPL(pcm512x_remove); + +/* TODO -+static int pcm512x_suspend(struct device *dev) -+{ -+ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, -+ PCM512x_RQPD, PCM512x_RQPD); -+ if (ret != 0) { -+ dev_err(dev, "Failed to request power down: %d\n", ret); -+ return ret; -+ } -+ -+ ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), -+ pcm512x->supplies); -+ if (ret != 0) { -+ dev_err(dev, "Failed to disable supplies: %d\n", ret); -+ return ret; -+ } -+ -+ if (!IS_ERR(pcm512x->sclk)) -+ clk_disable_unprepare(pcm512x->sclk); -+ -+ return 0; -+} -+ -+static int pcm512x_resume(struct device *dev) -+{ -+ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); -+ int ret; -+ -+ if (!IS_ERR(pcm512x->sclk)) { -+ ret = clk_prepare_enable(pcm512x->sclk); -+ if (ret != 0) { -+ dev_err(dev, "Failed to enable SCLK: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), -+ pcm512x->supplies); -+ if (ret != 0) { -+ dev_err(dev, "Failed to enable supplies: %d\n", ret); -+ return ret; -+ } -+ -+ regcache_cache_only(pcm512x->regmap, false); -+ ret = regcache_sync(pcm512x->regmap); -+ if (ret != 0) { -+ dev_err(dev, "Failed to sync cache: %d\n", ret); -+ return ret; -+ } -+ -+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, -+ PCM512x_RQPD, 0); -+ if (ret != 0) { -+ dev_err(dev, "Failed to remove power down: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ + static int pcm512x_suspend(struct device *dev) + { + struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); +@@ -579,10 +553,125 @@ static int pcm512x_resume(struct device *dev) + return 0; + } + +-const struct dev_pm_ops pcm512x_pm_ops = { +// END OF PCM512x_suspend and resume calls TODO +*/ + +static const struct dev_pm_ops pcm512x_pm_ops = { -+ SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) -+}; + SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) + }; +-EXPORT_SYMBOL_GPL(pcm512x_pm_ops); + +#if IS_ENABLED(CONFIG_I2C) +static int pcm512x_i2c_probe(struct i2c_client *i2c, @@ -110643,39 +113748,93 @@ index 0000000..55b6200 +#endif +} +module_exit(pcm512x_exit); -+ -+MODULE_DESCRIPTION("ASoC PCM512x codec driver"); -+MODULE_AUTHOR("Mark Brown "); -+MODULE_LICENSE("GPL v2"); + + MODULE_DESCRIPTION("ASoC PCM512x codec driver"); + MODULE_AUTHOR("Mark Brown "); diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h -new file mode 100644 -index 0000000..b2f518e ---- /dev/null +index 6ee76aa..b2f518e 100644 +--- a/sound/soc/codecs/pcm512x.h +++ b/sound/soc/codecs/pcm512x.h -@@ -0,0 +1,142 @@ -+/* -+ * Driver for the PCM512x CODECs -+ * -+ * Author: Mark Brown -+ * Copyright 2014 Linaro Ltd -+ * -+ * 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. -+ */ -+ -+#ifndef _SND_SOC_PCM512X -+#define _SND_SOC_PCM512X -+ +@@ -17,81 +17,66 @@ + #ifndef _SND_SOC_PCM512X + #define _SND_SOC_PCM512X + +-#include +-#include +- +-#define PCM512x_VIRT_BASE 0x100 +-#define PCM512x_PAGE_LEN 0x100 +-#define PCM512x_PAGE_BASE(n) (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n)) +#define PCM512x_PAGE_0_BASE 0 -+ -+#define PCM512x_PAGE 0 -+ + + #define PCM512x_PAGE 0 + +-#define PCM512x_RESET (PCM512x_PAGE_BASE(0) + 1) +-#define PCM512x_POWER (PCM512x_PAGE_BASE(0) + 2) +-#define PCM512x_MUTE (PCM512x_PAGE_BASE(0) + 3) +-#define PCM512x_PLL_EN (PCM512x_PAGE_BASE(0) + 4) +-#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) + 6) +-#define PCM512x_DSP (PCM512x_PAGE_BASE(0) + 7) +-#define PCM512x_GPIO_EN (PCM512x_PAGE_BASE(0) + 8) +-#define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_BASE(0) + 9) +-#define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_BASE(0) + 10) +-#define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) +-#define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) +-#define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) +-#define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_BASE(0) + 21) +-#define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_BASE(0) + 22) +-#define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_BASE(0) + 23) +-#define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_BASE(0) + 24) +-#define PCM512x_DSP_CLKDIV (PCM512x_PAGE_BASE(0) + 27) +-#define PCM512x_DAC_CLKDIV (PCM512x_PAGE_BASE(0) + 28) +-#define PCM512x_NCP_CLKDIV (PCM512x_PAGE_BASE(0) + 29) +-#define PCM512x_OSR_CLKDIV (PCM512x_PAGE_BASE(0) + 30) +-#define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_BASE(0) + 32) +-#define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_BASE(0) + 33) +-#define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_BASE(0) + 34) +-#define PCM512x_IDAC_1 (PCM512x_PAGE_BASE(0) + 35) +-#define PCM512x_IDAC_2 (PCM512x_PAGE_BASE(0) + 36) +-#define PCM512x_ERROR_DETECT (PCM512x_PAGE_BASE(0) + 37) +-#define PCM512x_I2S_1 (PCM512x_PAGE_BASE(0) + 40) +-#define PCM512x_I2S_2 (PCM512x_PAGE_BASE(0) + 41) +-#define PCM512x_DAC_ROUTING (PCM512x_PAGE_BASE(0) + 42) +-#define PCM512x_DSP_PROGRAM (PCM512x_PAGE_BASE(0) + 43) +-#define PCM512x_CLKDET (PCM512x_PAGE_BASE(0) + 44) +-#define PCM512x_AUTO_MUTE (PCM512x_PAGE_BASE(0) + 59) +-#define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_BASE(0) + 60) +-#define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_BASE(0) + 61) +-#define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_BASE(0) + 62) +-#define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_BASE(0) + 63) +-#define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_BASE(0) + 64) +-#define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_BASE(0) + 65) +-#define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_BASE(0) + 80) +-#define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_BASE(0) + 81) +-#define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_BASE(0) + 82) +-#define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_BASE(0) + 83) +-#define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_BASE(0) + 84) +-#define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_BASE(0) + 85) +-#define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_BASE(0) + 86) +-#define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_BASE(0) + 87) +-#define PCM512x_OVERFLOW (PCM512x_PAGE_BASE(0) + 90) +-#define PCM512x_RATE_DET_1 (PCM512x_PAGE_BASE(0) + 91) +-#define PCM512x_RATE_DET_2 (PCM512x_PAGE_BASE(0) + 92) +-#define PCM512x_RATE_DET_3 (PCM512x_PAGE_BASE(0) + 93) +-#define PCM512x_RATE_DET_4 (PCM512x_PAGE_BASE(0) + 94) +-#define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_BASE(0) + 108) +-#define PCM512x_GPIN (PCM512x_PAGE_BASE(0) + 119) +-#define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_BASE(0) + 120) +- +-#define PCM512x_OUTPUT_AMPLITUDE (PCM512x_PAGE_BASE(1) + 1) +-#define PCM512x_ANALOG_GAIN_CTRL (PCM512x_PAGE_BASE(1) + 2) +-#define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) + 5) +-#define PCM512x_ANALOG_MUTE_CTRL (PCM512x_PAGE_BASE(1) + 6) +-#define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) + 7) +-#define PCM512x_VCOM_CTRL_1 (PCM512x_PAGE_BASE(1) + 8) +-#define PCM512x_VCOM_CTRL_2 (PCM512x_PAGE_BASE(1) + 9) +- +-#define PCM512x_CRAM_CTRL (PCM512x_PAGE_BASE(44) + 1) +- +-#define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(44) + 1) +#define PCM512x_RESET (PCM512x_PAGE_0_BASE + 1) +#define PCM512x_POWER (PCM512x_PAGE_0_BASE + 2) +#define PCM512x_MUTE (PCM512x_PAGE_0_BASE + 3) @@ -110732,77 +113891,36 @@ index 0000000..b2f518e +#define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_0_BASE + 120) + +#define PCM512x_MAX_REGISTER (PCM512x_PAGE_0_BASE + 120) -+ -+/* Page 0, Register 1 - reset */ -+#define PCM512x_RSTR (1 << 0) -+#define PCM512x_RSTM (1 << 4) -+ -+/* Page 0, Register 2 - power */ -+#define PCM512x_RQPD (1 << 0) -+#define PCM512x_RQPD_SHIFT 0 -+#define PCM512x_RQST (1 << 4) -+#define PCM512x_RQST_SHIFT 4 -+ -+/* Page 0, Register 3 - mute */ -+#define PCM512x_RQMR_SHIFT 0 -+#define PCM512x_RQML_SHIFT 4 -+ -+/* Page 0, Register 4 - PLL */ -+#define PCM512x_PLCE (1 << 0) -+#define PCM512x_RLCE_SHIFT 0 -+#define PCM512x_PLCK (1 << 4) -+#define PCM512x_PLCK_SHIFT 4 -+ -+/* Page 0, Register 7 - DSP */ -+#define PCM512x_SDSL (1 << 0) -+#define PCM512x_SDSL_SHIFT 0 -+#define PCM512x_DEMP (1 << 4) -+#define PCM512x_DEMP_SHIFT 4 -+ -+/* Page 0, Register 13 - PLL reference */ -+#define PCM512x_SREF (1 << 4) -+ -+/* Page 0, Register 37 - Error detection */ -+#define PCM512x_IPLK (1 << 0) -+#define PCM512x_DCAS (1 << 1) -+#define PCM512x_IDCM (1 << 2) -+#define PCM512x_IDCH (1 << 3) -+#define PCM512x_IDSK (1 << 4) -+#define PCM512x_IDBK (1 << 5) -+#define PCM512x_IDFS (1 << 6) -+ -+/* Page 0, Register 42 - DAC routing */ -+#define PCM512x_AUPR_SHIFT 0 -+#define PCM512x_AUPL_SHIFT 4 -+ -+/* Page 0, Register 59 - auto mute */ -+#define PCM512x_ATMR_SHIFT 0 -+#define PCM512x_ATML_SHIFT 4 -+ -+/* Page 0, Register 63 - ramp rates */ -+#define PCM512x_VNDF_SHIFT 6 -+#define PCM512x_VNDS_SHIFT 4 -+#define PCM512x_VNUF_SHIFT 2 -+#define PCM512x_VNUS_SHIFT 0 -+ -+/* Page 0, Register 64 - emergency ramp rates */ -+#define PCM512x_VEDF_SHIFT 6 -+#define PCM512x_VEDS_SHIFT 4 -+ -+/* Page 0, Register 65 - Digital mute enables */ -+#define PCM512x_ACTL_SHIFT 2 -+#define PCM512x_AMLE_SHIFT 1 -+#define PCM512x_AMLR_SHIFT 0 -+ -+#endif + + /* Page 0, Register 1 - reset */ + #define PCM512x_RSTR (1 << 0) +@@ -154,18 +139,4 @@ + #define PCM512x_AMLE_SHIFT 1 + #define PCM512x_AMLR_SHIFT 0 + +-/* Page 1, Register 2 - analog volume control */ +-#define PCM512x_RAGN_SHIFT 0 +-#define PCM512x_LAGN_SHIFT 4 +- +-/* Page 1, Register 7 - analog boost control */ +-#define PCM512x_AGBR_SHIFT 0 +-#define PCM512x_AGBL_SHIFT 4 +- +-extern const struct dev_pm_ops pcm512x_pm_ops; +-extern const struct regmap_config pcm512x_regmap; +- +-int pcm512x_probe(struct device *dev, struct regmap *regmap); +-void pcm512x_remove(struct device *dev); +- + #endif -- 1.9.3 -From bb8eb42ce4b023f55c03a60be118fa1d318be310 Mon Sep 17 00:00:00 2001 +From 864325d1c4245cf3c0aed2aedf530d11b85db847 Mon Sep 17 00:00:00 2001 From: Howard Mitchell Date: Fri, 28 Mar 2014 16:27:57 +0000 -Subject: [PATCH 095/124] Fix volsw_range functions so SOC_DOUBLE_R_RANGE_TLV +Subject: [PATCH 50/53] Fix volsw_range functions so SOC_DOUBLE_R_RANGE_TLV works. This is so that the correct rabge of values as specified @@ -110813,10 +113931,10 @@ hardware for both the normal and invert cases. 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index fe1df50..c3f41e7 100644 +index 051c006..bf39f16 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c -@@ -3038,8 +3038,8 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, +@@ -3024,8 +3024,8 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; @@ -110827,7 +113945,7 @@ index fe1df50..c3f41e7 100644 return 0; } -@@ -3070,9 +3070,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, +@@ -3056,9 +3056,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, unsigned int val, val_mask; int ret; @@ -110840,7 +113958,7 @@ index fe1df50..c3f41e7 100644 val_mask = mask << shift; val = val << shift; -@@ -3081,9 +3082,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, +@@ -3067,9 +3068,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, return ret; if (snd_soc_volsw_is_stereo(mc)) { @@ -110853,7 +113971,7 @@ index fe1df50..c3f41e7 100644 val_mask = mask << shift; val = val << shift; -@@ -3121,18 +3123,14 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, +@@ -3107,18 +3109,14 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, (snd_soc_read(codec, reg) >> shift) & mask; if (invert) ucontrol->value.integer.value[0] = @@ -110878,68 +113996,21 @@ index fe1df50..c3f41e7 100644 1.9.3 -From 75e416111934573d8827d42021ec7c98c8d9aede Mon Sep 17 00:00:00 2001 -From: Howard Mitchell -Date: Fri, 28 Mar 2014 16:40:31 +0000 -Subject: [PATCH 096/124] Use a range macro for Playback Volume. - -This allows limiting the output gain to avoid clipping in the -DAC ouput stages. ---- - sound/soc/codecs/pcm512x.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c -index 55b6200..2653311 100644 ---- a/sound/soc/codecs/pcm512x.c -+++ b/sound/soc/codecs/pcm512x.c -@@ -240,8 +240,8 @@ static const struct soc_enum pcm512x_veds = - pcm512x_ramp_step_text); - - static const struct snd_kcontrol_new pcm512x_controls[] = { --SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, -- PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), -+SOC_DOUBLE_R_RANGE_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, -+ PCM512x_DIGITAL_VOLUME_3, 0, 48, 255, 1, digital_tlv), - SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, - PCM512x_RQMR_SHIFT, 1, 1), - --- -1.9.3 - - -From 0e36ddde822d82c1756ae736e74d530c634c5875 Mon Sep 17 00:00:00 2001 +From 58adc022393093e4088fa635ec89676478db3770 Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sun, 30 Mar 2014 13:52:33 +0100 -Subject: [PATCH 097/124] fix soc-core's inverse range and let IQaudIO DAC use +Subject: [PATCH 51/53] fix soc-core's inverse range and let IQaudIO DAC use this fixed SOC_DOUBLE_R_RANGE_TLV support --- - sound/soc/codecs/pcm512x.c | 3 ++- - sound/soc/soc-core.c | 8 ++++---- - 2 files changed, 6 insertions(+), 5 deletions(-) + sound/soc/soc-core.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) -diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c -index 2653311..b669e15 100644 ---- a/sound/soc/codecs/pcm512x.c -+++ b/sound/soc/codecs/pcm512x.c -@@ -239,9 +239,10 @@ static const struct soc_enum pcm512x_veds = - SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, - pcm512x_ramp_step_text); - -+/* Don't let the DAC go into clipping by limiting the alsa volume control range */ - static const struct snd_kcontrol_new pcm512x_controls[] = { - SOC_DOUBLE_R_RANGE_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, -- PCM512x_DIGITAL_VOLUME_3, 0, 48, 255, 1, digital_tlv), -+ PCM512x_DIGITAL_VOLUME_3, 0, 40, 255, 1, digital_tlv), - SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, - PCM512x_RQMR_SHIFT, 1, 1), - diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index c3f41e7..a8a753f 100644 +index bf39f16..4d8917b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c -@@ -3072,8 +3072,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, +@@ -3058,8 +3058,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, if (invert) val = ((max - ucontrol->value.integer.value[0] + min) & mask); @@ -110950,7 +114021,7 @@ index c3f41e7..a8a753f 100644 val_mask = mask << shift; val = val << shift; -@@ -3084,8 +3084,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, +@@ -3070,8 +3070,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, if (snd_soc_volsw_is_stereo(mc)) { if (invert) val = ((max - ucontrol->value.integer.value[1] + min) & mask); @@ -110965,6005 +114036,10 @@ index c3f41e7..a8a753f 100644 1.9.3 -From ed9050b37b3de619539eaf8a0b8c11fb55f9957e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 22 Apr 2014 13:58:14 +0100 -Subject: [PATCH 098/124] lirc_rpi: Use read_current_timer to determine - transmitter delay. Thanks to jjmz and others See: - https://github.com/raspberrypi/linux/issues/525 - ---- - drivers/staging/media/lirc/lirc_rpi.c | 32 +++++++++++++++++--------------- - 1 file changed, 17 insertions(+), 15 deletions(-) - -diff --git a/drivers/staging/media/lirc/lirc_rpi.c b/drivers/staging/media/lirc/lirc_rpi.c -index 8aee83f..57ffacf 100644 ---- a/drivers/staging/media/lirc/lirc_rpi.c -+++ b/drivers/staging/media/lirc/lirc_rpi.c -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -41,7 +42,7 @@ - - #define LIRC_DRIVER_NAME "lirc_rpi" - #define RBUF_LEN 256 --#define LIRC_TRANSMITTER_LATENCY 256 -+#define LIRC_TRANSMITTER_LATENCY 50 - - #ifndef MAX_UDELAY_MS - #define MAX_UDELAY_US 5000 -@@ -107,19 +108,15 @@ static void safe_udelay(unsigned long usecs) - static int init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) - { -- /* -- * period, pulse/space width are kept with 8 binary places - -- * IE multiplied by 256. -- */ -- if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= -+ if (1000 * 1000000L / new_freq * new_duty_cycle / 100 <= - LIRC_TRANSMITTER_LATENCY) - return -EINVAL; -- if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= -+ if (1000 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= - LIRC_TRANSMITTER_LATENCY) - return -EINVAL; - duty_cycle = new_duty_cycle; - freq = new_freq; -- period = 256 * 1000000L / freq; -+ period = 1000 * 1000000L / freq; - pulse_width = period * duty_cycle / 100; - space_width = period - pulse_width; - dprintk("in init_timing_params, freq=%d pulse=%ld, " -@@ -130,11 +127,14 @@ static int init_timing_params(unsigned int new_duty_cycle, - static long send_pulse_softcarrier(unsigned long length) - { - int flag; -- unsigned long actual, target, d; -+ unsigned long actual, target; -+ unsigned long actual_us, initial_us, target_us; - -- length <<= 8; -+ length *= 1000; - - actual = 0; target = 0; flag = 0; -+ read_current_timer(&actual_us); -+ - while (actual < length) { - if (flag) { - gpiochip->set(gpiochip, gpio_out_pin, invert); -@@ -143,17 +143,19 @@ static long send_pulse_softcarrier(unsigned long length) - gpiochip->set(gpiochip, gpio_out_pin, !invert); - target += pulse_width; - } -- d = (target - actual - -- LIRC_TRANSMITTER_LATENCY + 128) >> 8; -+ initial_us = actual_us; -+ target_us = actual_us + (target - actual) / 1000; - /* - * Note - we've checked in ioctl that the pulse/space - * widths are big enough so that d is > 0 - */ -- udelay(d); -- actual += (d << 8) + LIRC_TRANSMITTER_LATENCY; -+ if ((int)(target_us - actual_us) > 0) -+ udelay(target_us - actual_us); -+ read_current_timer(&actual_us); -+ actual += (actual_us - initial_us) * 1000; - flag = !flag; - } -- return (actual-length) >> 8; -+ return (actual-length) / 1000; - } - - static long send_pulse(unsigned long length) --- -1.9.3 - - -From 4e62ab8ee6fdcc9dad1fb2562f99ab4f86ca03d0 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Wed, 19 Mar 2014 15:13:53 +0000 -Subject: [PATCH 099/124] Fix ARM architecture issue with local_irq_restore() - -If local_fiq_enable() is called before a local_irq_restore(flags) where -the flags variable has the F bit set, the FIQ will be erroneously disabled. - -Fixup arch_local_irq_restore to avoid trampling the F bit in CPSR. - -Also fix some of the hacks previously implemented for previous dwc_otg -incarnations. ---- - arch/arm/include/asm/fiq.h | 1 - - arch/arm/include/asm/irqflags.h | 16 +++++++++++++--- - arch/arm/kernel/fiq.c | 1 - - arch/arm/kernel/fiqasm.S | 3 --- - drivers/usb/host/dwc_common_port/dwc_common_linux.c | 1 + - 5 files changed, 14 insertions(+), 8 deletions(-) - -diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h -index f1a131b..d493d0b 100644 ---- a/arch/arm/include/asm/fiq.h -+++ b/arch/arm/include/asm/fiq.h -@@ -42,7 +42,6 @@ extern void disable_fiq(int fiq); - /* helpers defined in fiqasm.S: */ - extern void __set_fiq_regs(unsigned long const *regs); - extern void __get_fiq_regs(unsigned long *regs); --extern void __FIQ_Branch(unsigned long *regs); - - static inline void set_fiq_regs(struct pt_regs const *regs) - { -diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h -index 3b763d6..5770408 100644 ---- a/arch/arm/include/asm/irqflags.h -+++ b/arch/arm/include/asm/irqflags.h -@@ -145,12 +145,22 @@ static inline unsigned long arch_local_save_flags(void) - } - - /* -- * restore saved IRQ & FIQ state -+ * restore saved IRQ state - */ - static inline void arch_local_irq_restore(unsigned long flags) - { -- asm volatile( -- " msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore" -+ unsigned long temp = 0; -+ flags &= ~(1 << 6); -+ asm volatile ( -+ " mrs %0, cpsr" -+ : "=r" (temp) -+ : -+ : "memory", "cc"); -+ /* Preserve FIQ bit */ -+ temp &= (1 << 6); -+ flags = flags | temp; -+ asm volatile ( -+ " msr cpsr_c, %0 @ local_irq_restore" - : - : "r" (flags) - : "memory", "cc"); -diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c -index aac11f8..918875d 100644 ---- a/arch/arm/kernel/fiq.c -+++ b/arch/arm/kernel/fiq.c -@@ -142,7 +142,6 @@ void disable_fiq(int fiq) - EXPORT_SYMBOL(set_fiq_handler); - EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */ - EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */ --EXPORT_SYMBOL(__FIQ_Branch); /* defined in fiqasm.S */ - EXPORT_SYMBOL(claim_fiq); - EXPORT_SYMBOL(release_fiq); - EXPORT_SYMBOL(enable_fiq); -diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S -index 93eddfe..5233d54 100644 ---- a/arch/arm/kernel/fiqasm.S -+++ b/arch/arm/kernel/fiqasm.S -@@ -25,9 +25,6 @@ - ENTRY(__set_fiq_regs) - mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE - mrs r1, cpsr --@@@@@@@@@@@@@@@ hack: enable the fiq here to keep usb driver happy -- and r1, #~PSR_F_BIT --@@@@@@@@@@@@@@@ endhack: (need to find better place for this to happen) - msr cpsr_c, r2 @ select FIQ mode - mov r0, r0 @ avoid hazard prior to ARMv4 - ldmia r0!, {r8 - r12} -diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -index 0812d3a..6d01261 100644 ---- a/drivers/usb/host/dwc_common_port/dwc_common_linux.c -+++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -@@ -585,6 +585,7 @@ void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_ - local_irq_save(flags); - local_fiq_disable(); - writel((readl(reg) & ~clear_mask) | set_mask, reg); -+ local_fiq_enable(); - local_irq_restore(flags); - } - --- -1.9.3 - - -From 33e65bbe3cf3427151acbe8f8fc0475865a4a047 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Wed, 19 Mar 2014 12:58:23 +0000 -Subject: [PATCH 100/124] dwc_otg: fiq_fsm: Base commit for driver rewrite - -This commit removes the previous FIQ fixes entirely and adds fiq_fsm. - -This rewrite features much more complete support for split transactions -and takes into account several OTG hardware bugs. High-speed -isochronous transactions are also capable of being performed by fiq_fsm. - -All driver options have been removed and replaced with: - - dwc_otg.fiq_enable (bool) - - dwc_otg.fiq_fsm_enable (bool) - - dwc_otg.fiq_fsm_mask (bitmask) - - dwc_otg.nak_holdoff (unsigned int) - -Defaults are specified such that fiq_fsm behaves similarly to the -previously implemented FIQ fixes. - -fiq_fsm: Push error recovery into the FIQ when fiq_fsm is used - -If the transfer associated with a QTD failed due to a bus error, the HCD -would retry the transfer up to 3 times (implementing the USB2.0 -three-strikes retry in software). - -Due to the masking mechanism used by fiq_fsm, it is only possible to pass -a single interrupt through to the HCD per-transfer. - -In this instance host channels would fall off the radar because the error -reset would function, but the subsequent channel halt would be lost. - -Push the error count reset into the FIQ handler. - -fiq_fsm: Implement timeout mechanism - -For full-speed endpoints with a large packet size, interrupt latency -runs the risk of the FIQ starting a transaction too late in a full-speed -frame. If the device is still transmitting data when EOF2 for the -downstream frame occurs, the hub will disable the port. This change is -not reflected in the hub status endpoint and the device becomes -unresponsive. - -Prevent high-bandwidth transactions from being started too late in a -frame. The mechanism is not guaranteed: a combination of bit stuffing -and hub latency may still result in a device overrunning. - -fiq_fsm: fix bounce buffer utilisation for Isochronous OUT - -Multi-packet isochronous OUT transactions were subject to a few bounday -bugs. Fix them. - -Audio playback is now much more robust: however, an issue stands with -devices that have adaptive sinks - ALSA plays samples too fast. - -dwc_otg: Return full-speed frame numbers in HS mode - -The frame counter increments on every *microframe* in high-speed mode. -Most device drivers expect this number to be in full-speed frames - this -caused considerable confusion to e.g. snd_usb_audio which uses the -frame counter to estimate the number of samples played. - -fiq_fsm: save PID on completion of interrupt OUT transfers - -Also add edge case handling for interrupt transports. - -Note that for periodic split IN, data toggles are unimplemented in the -OTG host hardware - it unconditionally accepts any PID. - -fiq_fsm: add missing case for fiq_fsm_tt_in_use() - -Certain combinations of bitrate and endpoint activity could -result in a periodic transaction erroneously getting started -while the previous Isochronous OUT was still active. - -fiq_fsm: clear hcintmsk for aborted transactions - -Prevents the FIQ from erroneously handling interrupts -on a timed out channel. - -fiq_fsm: enable by default ---- - arch/arm/mach-bcm2708/bcm2708.c | 19 - - drivers/usb/host/dwc_otg/Makefile | 3 +- - drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 47 +- - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 47 +- - drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 1293 ++++++++++++++++++++++++++ - drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 353 +++++++ - drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S | 81 ++ - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 765 ++++++++++++--- - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 11 + - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 986 +++++++++----------- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 109 ++- - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 41 +- - drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c | 113 --- - drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h | 48 - - 14 files changed, 2964 insertions(+), 952 deletions(-) - create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c - create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h - create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S - delete mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c - delete mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index c6f04df..887f732 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -328,20 +328,6 @@ static struct resource bcm2708_usb_resources[] = { - }, - }; - --bool fiq_fix_enable = true; -- --static struct resource bcm2708_usb_resources_no_fiq_fix[] = { -- [0] = { -- .start = USB_BASE, -- .end = USB_BASE + SZ_128K - 1, -- .flags = IORESOURCE_MEM, -- }, -- [1] = { -- .start = IRQ_USB, -- .end = IRQ_USB, -- .flags = IORESOURCE_IRQ, -- }, --}; - - static u64 usb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); - -@@ -805,11 +791,6 @@ void __init bcm2708_init(void) - #endif - bcm_register_device(&bcm2708_systemtimer_device); - bcm_register_device(&bcm2708_fb_device); -- if (!fiq_fix_enable) -- { -- bcm2708_usb_device.resource = bcm2708_usb_resources_no_fiq_fix; -- bcm2708_usb_device.num_resources = ARRAY_SIZE(bcm2708_usb_resources_no_fiq_fix); -- } - bcm_register_device(&bcm2708_usb_device); - bcm_register_device(&bcm2708_uart1_device); - bcm_register_device(&bcm2708_powerman_device); -diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile -index a56f193..e7bdd12 100644 ---- a/drivers/usb/host/dwc_otg/Makefile -+++ b/drivers/usb/host/dwc_otg/Makefile -@@ -36,7 +36,8 @@ dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o - dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o - dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o - dwc_otg-objs += dwc_otg_adp.o --dwc_otg-objs += dwc_otg_mphi_fix.o -+dwc_otg-objs += dwc_otg_fiq_fsm.o -+dwc_otg-objs += dwc_otg_fiq_stub.o - ifneq ($(CFI),) - dwc_otg-objs += dwc_otg_cfi.o - endif -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -index 2f8b3bd..065807f 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c -@@ -45,7 +45,6 @@ - #include "dwc_otg_driver.h" - #include "dwc_otg_pcd.h" - #include "dwc_otg_hcd.h" --#include "dwc_otg_mphi_fix.h" - - #ifdef DEBUG - inline const char *op_state_str(dwc_otg_core_if_t * core_if) -@@ -1319,7 +1318,7 @@ static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if) - /** - * This function returns the Core Interrupt register. - */ --static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gintmsk_data_t *reenable_gintmsk) -+static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gintmsk_data_t *reenable_gintmsk, dwc_otg_hcd_t *hcd) - { - gahbcfg_data_t gahbcfg = {.d32 = 0 }; - gintsts_data_t gintsts; -@@ -1345,16 +1344,15 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gin - } - gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts); - gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk); -- { -- unsigned long flags; -- -- // Re-enable the saved interrupts -- local_irq_save(flags); -+ if(fiq_enable) { - local_fiq_disable(); -- gintmsk.d32 |= gintmsk_common.d32; -- gintsts_saved.d32 &= ~gintmsk_common.d32; -- reenable_gintmsk->d32 = gintmsk.d32; -- local_irq_restore(flags); -+ /* Pull in the interrupts that the FIQ has masked */ -+ gintmsk.d32 |= ~(hcd->fiq_state->gintmsk_saved.d32); -+ /* for the upstairs function to reenable - have to read it here in case FIQ triggers again */ -+ reenable_gintmsk->d32 |= gintmsk.d32; -+ reenable_gintmsk->d32 |= ~(hcd->fiq_state->gintmsk_saved.d32); -+ reenable_gintmsk->d32 &= gintmsk_common.d32; -+ local_fiq_enable(); - } - - gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg); -@@ -1366,13 +1364,15 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gin - gintsts.d32, gintmsk.d32); - } - #endif -- if (!fiq_fix_enable){ -+ if (!fiq_enable){ - if (gahbcfg.b.glblintrmsk) - return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); - else - return 0; -- } -- else { -+ } else { -+ /* Our IRQ kicker is no longer the USB hardware, it's the MPHI interface. -+ * Can't trust the global interrupt mask bit in this case. -+ */ - return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); - } - -@@ -1406,7 +1406,7 @@ int32_t dwc_otg_handle_common_intr(void *dev) - { - int retval = 0; - gintsts_data_t gintsts; -- gintmsk_data_t reenable_gintmsk; -+ gintmsk_data_t gintmsk_reenable = { .d32 = 0 }; - gpwrdn_data_t gpwrdn = {.d32 = 0 }; - dwc_otg_device_t *otg_dev = dev; - dwc_otg_core_if_t *core_if = otg_dev->core_if; -@@ -1428,7 +1428,10 @@ int32_t dwc_otg_handle_common_intr(void *dev) - } - - if (core_if->hibernation_suspend <= 0) { -- gintsts.d32 = dwc_otg_read_common_intr(core_if, &reenable_gintmsk); -+ /* read_common will have to poke the FIQ's saved mask. We must then clear this mask at the end -+ * of this handler - god only knows why it's done like this -+ */ -+ gintsts.d32 = dwc_otg_read_common_intr(core_if, &gintmsk_reenable, otg_dev->hcd); - - if (gintsts.b.modemismatch) { - retval |= dwc_otg_handle_mode_mismatch_intr(core_if); -@@ -1525,11 +1528,16 @@ int32_t dwc_otg_handle_common_intr(void *dev) - gintsts.b.portintr = 1; - DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32); - retval |= 1; -- reenable_gintmsk.b.portintr = 1; -+ gintmsk_reenable.b.portintr = 1; - - } -- -- DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, reenable_gintmsk.d32); -+ /* Did we actually handle anything? if so, unmask the interrupt */ -+// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "CILOUT %1d", retval); -+// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintsts.d32); -+// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintmsk_reenable.d32); -+ if (retval) { -+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_reenable.d32); -+ } - - } else { - DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32); -@@ -1583,6 +1591,5 @@ int32_t dwc_otg_handle_common_intr(void *dev) - } - if (core_if->lock) - DWC_SPINUNLOCK(core_if->lock); -- - return retval; - } -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index f06c3d22..bbf63a4 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -56,6 +56,7 @@ - #include "dwc_otg_core_if.h" - #include "dwc_otg_pcd_if.h" - #include "dwc_otg_hcd_if.h" -+#include "dwc_otg_fiq_fsm.h" - - #define DWC_DRIVER_VERSION "3.00a 10-AUG-2012" - #define DWC_DRIVER_DESC "HS OTG USB Controller driver" -@@ -64,7 +65,6 @@ bool microframe_schedule=true; - - static const char dwc_driver_name[] = "dwc_otg"; - --extern void* dummy_send; - - extern int pcd_init( - #ifdef LM_INTERFACE -@@ -240,13 +240,14 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { - .adp_enable = -1, - }; - --//Global variable to switch the fiq fix on or off (declared in bcm2708.c) --extern bool fiq_fix_enable; -+//Global variable to switch the fiq fix on or off -+bool fiq_enable = 1; - // Global variable to enable the split transaction fix --bool fiq_split_enable = true; --//Global variable to switch the nak holdoff on or off --bool nak_holdoff_enable = true; -+bool fiq_fsm_enable = true; -+//Bulk split-transaction NAK holdoff in microframes -+uint16_t nak_holdoff = 8; - -+unsigned short fiq_fsm_mask = 0x07; - - /** - * This function shows the Driver Version. -@@ -800,7 +801,7 @@ static int dwc_otg_driver_probe( - dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start, - _dev->resource[0].end - - _dev->resource[0].start+1); -- if (fiq_fix_enable) -+ if (fiq_enable) - { - if (!request_mem_region(_dev->resource[1].start, - _dev->resource[1].end - _dev->resource[1].start + 1, -@@ -813,7 +814,6 @@ static int dwc_otg_driver_probe( - dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start, - _dev->resource[1].end - - _dev->resource[1].start + 1); -- dummy_send = (void *) kmalloc(16, GFP_ATOMIC); - } - - #else -@@ -1071,9 +1071,9 @@ static int __init dwc_otg_driver_init(void) - int error; - struct device_driver *drv; - -- if(fiq_split_enable && !fiq_fix_enable) { -- printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n"); -- fiq_fix_enable = 1; -+ if(fiq_fsm_enable && !fiq_enable) { -+ printk(KERN_WARNING "dwc_otg: fiq_fsm_enable was set without fiq_enable! Correcting.\n"); -+ fiq_enable = 1; - } - - printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name, -@@ -1095,9 +1095,9 @@ static int __init dwc_otg_driver_init(void) - printk(KERN_ERR "%s retval=%d\n", __func__, retval); - return retval; - } -- printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled"); -- printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled"); -- printk(KERN_DEBUG "dwc_otg: FIQ split fix %s\n", fiq_split_enable ? "enabled":"disabled"); -+ printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_enable ? "enabled":"disabled"); -+ printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff ? "enabled":"disabled"); -+ printk(KERN_DEBUG "dwc_otg: FIQ split-transaction FSM %s\n", fiq_fsm_enable ? "enabled":"disabled"); - - error = driver_create_file(drv, &driver_attr_version); - #ifdef DEBUG -@@ -1378,12 +1378,19 @@ MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0"); - module_param(microframe_schedule, bool, 0444); - MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler"); - --module_param(fiq_fix_enable, bool, 0444); --MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix"); --module_param(nak_holdoff_enable, bool, 0444); --MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff"); --module_param(fiq_split_enable, bool, 0444); --MODULE_PARM_DESC(fiq_split_enable, "Enable the FIQ fix on split transactions"); -+module_param(fiq_enable, bool, 0444); -+MODULE_PARM_DESC(fiq_enable, "Enable the FIQ"); -+module_param(nak_holdoff, ushort, 0644); -+MODULE_PARM_DESC(nak_holdoff, "Throttle duration for bulk split-transaction endpoints on a NAK. Default 8"); -+module_param(fiq_fsm_enable, bool, 0444); -+MODULE_PARM_DESC(fiq_fsm_enable, "Enable the FIQ to perform split transactions as defined by fiq_fsm_mask"); -+module_param(fiq_fsm_mask, ushort, 0444); -+MODULE_PARM_DESC(fiq_fsm_mask, "Bitmask of transactions to perform in the FIQ.\n" -+ "Bit 0 : Non-periodic split transactions\n" -+ "Bit 1 : Periodic split transactions\n" -+ "Bit 2 : High-speed multi-transfer isochronous\n" -+ "All other bits should be set 0."); -+ - - /** @page "Module Parameters" - * -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -new file mode 100644 -index 0000000..61f5534 ---- /dev/null -+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -@@ -0,0 +1,1293 @@ -+/* -+ * dwc_otg_fiq_fsm.c - The finite state machine FIQ -+ * -+ * Copyright (c) 2013 Raspberry Pi Foundation -+ * -+ * Author: Jonathan Bell -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * * Neither the name of Raspberry Pi nor the -+ * names of its contributors may be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This FIQ implements functionality that performs split transactions on -+ * the dwc_otg hardware without any outside intervention. A split transaction -+ * is "queued" by nominating a specific host channel to perform the entirety -+ * of a split transaction. This FIQ will then perform the microframe-precise -+ * scheduling required in each phase of the transaction until completion. -+ * -+ * The FIQ functionality is glued into the Synopsys driver via the entry point -+ * in the FSM enqueue function, and at the exit point in handling a HC interrupt -+ * for a FSM-enabled channel. -+ * -+ * NB: Large parts of this implementation have architecture-specific code. -+ * For porting this functionality to other ARM machines, the minimum is required: -+ * - An interrupt controller allowing the top-level dwc USB interrupt to be routed -+ * to the FIQ -+ * - A method of forcing a software generated interrupt from FIQ mode that then -+ * triggers an IRQ entry (with the dwc USB handler called by this IRQ number) -+ * - Guaranteed interrupt routing such that both the FIQ and SGI occur on the same -+ * processor core - there is no locking between the FIQ and IRQ (aside from -+ * local_fiq_disable) -+ * -+ */ -+ -+#include "dwc_otg_fiq_fsm.h" -+ -+ -+char buffer[1000*16]; -+int wptr; -+void notrace _fiq_print(enum fiq_debug_level dbg_lvl, volatile struct fiq_state *state, char *fmt, ...) -+{ -+ enum fiq_debug_level dbg_lvl_req = FIQDBG_ERR; -+ va_list args; -+ char text[17]; -+ hfnum_data_t hfnum = { .d32 = FIQ_READ(state->dwc_regs_base + 0x408) }; -+ -+ if((dbg_lvl & dbg_lvl_req) || dbg_lvl == FIQDBG_ERR) -+ { -+ snprintf(text, 9, " %4d:%1u ", hfnum.b.frnum/8, hfnum.b.frnum & 7); -+ va_start(args, fmt); -+ vsnprintf(text+8, 9, fmt, args); -+ va_end(args); -+ -+ memcpy(buffer + wptr, text, 16); -+ wptr = (wptr + 16) % sizeof(buffer); -+ } -+} -+ -+/** -+ * fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction -+ * @channel: channel to re-enable -+ */ -+static void fiq_fsm_restart_channel(struct fiq_state *st, int n, int force) -+{ -+ hcchar_data_t hcchar = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR) }; -+ -+ hcchar.b.chen = 0; -+ if (st->channel[n].hcchar_copy.b.eptype & 0x1) { -+ hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; -+ /* Hardware bug workaround: update the ssplit index */ -+ if (st->channel[n].hcsplt_copy.b.spltena) -+ st->channel[n].expected_uframe = (hfnum.b.frnum + 1) & 0x3FFF; -+ -+ hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; -+ } -+ -+ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, hcchar.d32); -+ hcchar.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); -+ hcchar.b.chen = 1; -+ -+ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, hcchar.d32); -+ fiq_print(FIQDBG_INT, st, "HCGO %01d %01d", n, force); -+} -+ -+/** -+ * fiq_fsm_setup_csplit() - Prepare a host channel for a CSplit transaction stage -+ * @st: Pointer to the channel's state -+ * @n : channel number -+ * -+ * Change host channel registers to perform a complete-split transaction. Being mindful of the -+ * endpoint direction, set control regs up correctly. -+ */ -+static void notrace fiq_fsm_setup_csplit(struct fiq_state *st, int n) -+{ -+ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT) }; -+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; -+ -+ hcsplt.b.compsplt = 1; -+ if (st->channel[n].hcchar_copy.b.epdir == 1) { -+ // If IN, the CSPLIT result contains the data or a hub handshake. hctsiz = maxpacket. -+ hctsiz.b.xfersize = st->channel[n].hctsiz_copy.b.xfersize; -+ } else { -+ // If OUT, the CSPLIT result contains handshake only. -+ hctsiz.b.xfersize = 0; -+ } -+ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT, hcsplt.d32); -+ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); -+ mb(); -+} -+ -+static inline int notrace fiq_get_xfer_len(struct fiq_state *st, int n) -+{ -+ /* The xfersize register is a bit wonky. For IN transfers, it decrements by the packet size. */ -+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; -+ -+ if (st->channel[n].hcchar_copy.b.epdir == 0) { -+ return st->channel[n].hctsiz_copy.b.xfersize; -+ } else { -+ return st->channel[n].hctsiz_copy.b.xfersize - hctsiz.b.xfersize; -+ } -+ -+} -+ -+ -+/** -+ * fiq_increment_dma_buf() - update DMA address for bounce buffers after a CSPLIT -+ * -+ * Of use only for IN periodic transfers. -+ */ -+static int notrace fiq_increment_dma_buf(struct fiq_state *st, int num_channels, int n) -+{ -+ hcdma_data_t hcdma; -+ int i = st->channel[n].dma_info.index; -+ int len; -+ struct fiq_dma_blob *blob = (struct fiq_dma_blob *) st->dma_base; -+ -+ len = fiq_get_xfer_len(st, n); -+ fiq_print(FIQDBG_INT, st, "LEN: %03d", len); -+ st->channel[n].dma_info.slot_len[i] = len; -+ i++; -+ if (i > 6) -+ BUG(); -+ -+ hcdma.d32 = (dma_addr_t) &blob->channel[n].index[i].buf[0]; -+ FIQ_WRITE(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); -+ st->channel[n].dma_info.index = i; -+ return 0; -+} -+ -+/** -+ * fiq_reload_hctsiz() - for IN transactions, reset HCTSIZ -+ */ -+static void notrace fiq_fsm_reload_hctsiz(struct fiq_state *st, int n) -+{ -+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ) }; -+ hctsiz.b.xfersize = st->channel[n].hctsiz_copy.b.xfersize; -+ hctsiz.b.pktcnt = 1; -+ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); -+} -+ -+/** -+ * fiq_iso_out_advance() - update DMA address and split position bits -+ * for isochronous OUT transactions. -+ * -+ * Returns 1 if this is the last packet queued, 0 otherwise. Split-ALL and -+ * Split-BEGIN states are not handled - this is done when the transaction was queued. -+ * -+ * This function must only be called from the FIQ_ISO_OUT_ACTIVE state. -+ */ -+static int notrace fiq_iso_out_advance(struct fiq_state *st, int num_channels, int n) -+{ -+ hcsplt_data_t hcsplt; -+ hctsiz_data_t hctsiz; -+ hcdma_data_t hcdma; -+ struct fiq_dma_blob *blob = (struct fiq_dma_blob *) st->dma_base; -+ int last = 0; -+ int i = st->channel[n].dma_info.index; -+ -+ fiq_print(FIQDBG_INT, st, "ADV %01d %01d ", n, i); -+ i++; -+ if (i == 4) -+ last = 1; -+ if (st->channel[n].dma_info.slot_len[i+1] == 255) -+ last = 1; -+ -+ /* New DMA address - address of bounce buffer referred to in index */ -+ hcdma.d32 = (uint32_t) &blob->channel[n].index[i].buf[0]; -+ //hcdma.d32 = FIQ_READ(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n)); -+ //hcdma.d32 += st->channel[n].dma_info.slot_len[i]; -+ fiq_print(FIQDBG_INT, st, "LAST: %01d ", last); -+ fiq_print(FIQDBG_INT, st, "LEN: %03d", st->channel[n].dma_info.slot_len[i]); -+ hcsplt.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT); -+ hctsiz.d32 = FIQ_READ(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ); -+ hcsplt.b.xactpos = (last) ? ISOC_XACTPOS_END : ISOC_XACTPOS_MID; -+ /* Set up new packet length */ -+ hctsiz.b.pktcnt = 1; -+ hctsiz.b.xfersize = st->channel[n].dma_info.slot_len[i]; -+ fiq_print(FIQDBG_INT, st, "%08x", hctsiz.d32); -+ -+ st->channel[n].dma_info.index++; -+ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCSPLT, hcsplt.d32); -+ FIQ_WRITE(st->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, hctsiz.d32); -+ FIQ_WRITE(st->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); -+ return last; -+} -+ -+/** -+ * fiq_fsm_tt_next_isoc() - queue next pending isochronous out start-split on a TT -+ * -+ * Despite the limitations of the DWC core, we can force a microframe pipeline of -+ * isochronous OUT start-split transactions while waiting for a corresponding other-type -+ * of endpoint to finish its CSPLITs. TTs have big periodic buffers therefore it -+ * is very unlikely that filling the start-split FIFO will cause data loss. -+ * This allows much better interleaving of transactions in an order-independent way- -+ * there is no requirement to prioritise isochronous, just a state-space search has -+ * to be performed on each periodic start-split complete interrupt. -+ */ -+static int notrace fiq_fsm_tt_next_isoc(struct fiq_state *st, int num_channels, int n) -+{ -+ int hub_addr = st->channel[n].hub_addr; -+ int port_addr = st->channel[n].port_addr; -+ int i, poked = 0; -+ for (i = 0; i < num_channels; i++) { -+ if (i == n || st->channel[i].fsm == FIQ_PASSTHROUGH) -+ continue; -+ if (st->channel[i].hub_addr == hub_addr && -+ st->channel[i].port_addr == port_addr) { -+ switch (st->channel[i].fsm) { -+ case FIQ_PER_ISO_OUT_PENDING: -+ if (st->channel[i].nrpackets == 1) { -+ st->channel[i].fsm = FIQ_PER_ISO_OUT_LAST; -+ } else { -+ st->channel[i].fsm = FIQ_PER_ISO_OUT_ACTIVE; -+ } -+ fiq_fsm_restart_channel(st, i, 0); -+ poked = 1; -+ break; -+ -+ default: -+ break; -+ } -+ } -+ if (poked) -+ break; -+ } -+ return poked; -+} -+ -+/** -+ * fiq_fsm_tt_in_use() - search for host channels using this TT -+ * @n: Channel to use as reference -+ * -+ */ -+int notrace noinline fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n) -+{ -+ int hub_addr = st->channel[n].hub_addr; -+ int port_addr = st->channel[n].port_addr; -+ int i, in_use = 0; -+ for (i = 0; i < num_channels; i++) { -+ if (i == n || st->channel[i].fsm == FIQ_PASSTHROUGH) -+ continue; -+ switch (st->channel[i].fsm) { -+ /* TT is reserved for channels that are in the middle of a periodic -+ * split transaction. -+ */ -+ case FIQ_PER_SSPLIT_STARTED: -+ case FIQ_PER_CSPLIT_WAIT: -+ case FIQ_PER_CSPLIT_NYET1: -+ //case FIQ_PER_CSPLIT_POLL: -+ case FIQ_PER_ISO_OUT_ACTIVE: -+ case FIQ_PER_ISO_OUT_LAST: -+ if (st->channel[i].hub_addr == hub_addr && -+ st->channel[i].port_addr == port_addr) { -+ in_use = 1; -+ } -+ break; -+ default: -+ break; -+ } -+ if (in_use) -+ break; -+ } -+ return in_use; -+} -+ -+/** -+ * fiq_fsm_more_csplits() - determine whether additional CSPLITs need -+ * to be issued for this IN transaction. -+ * -+ * We cannot tell the inbound PID of a data packet due to hardware limitations. -+ * we need to make an educated guess as to whether we need to queue another CSPLIT -+ * or not. A no-brainer is when we have received enough data to fill the endpoint -+ * size, but for endpoints that give variable-length data then we have to resort -+ * to heuristics. -+ * -+ * We also return whether this is the last CSPLIT to be queued, again based on -+ * heuristics. This is to allow a 1-uframe overlap of periodic split transactions. -+ * Note: requires at least 1 CSPLIT to have been performed prior to being called. -+ */ -+ -+/* -+ * We need some way of guaranteeing if a returned periodic packet of size X -+ * has a DATA0 PID. -+ * The heuristic value of 144 bytes assumes that the received data has maximal -+ * bit-stuffing and the clock frequency of the transmitting device is at the lowest -+ * permissible limit. If the transfer length results in a final packet size -+ * 144 < p <= 188, then an erroneous CSPLIT will be issued. -+ * Also used to ensure that an endpoint will nominally only return a single -+ * complete-split worth of data. -+ */ -+#define DATA0_PID_HEURISTIC 144 -+ -+static int notrace noinline fiq_fsm_more_csplits(struct fiq_state *state, int n, int *probably_last) -+{ -+ -+ int i; -+ int total_len = 0; -+ int more_needed = 1; -+ struct fiq_channel_state *st = &state->channel[n]; -+ -+ for (i = 0; i < st->dma_info.index; i++) { -+ total_len += st->dma_info.slot_len[i]; -+ } -+ -+ *probably_last = 0; -+ -+ if (st->hcchar_copy.b.eptype == 0x3) { -+ /* -+ * An interrupt endpoint will take max 2 CSPLITs. if we are receiving data -+ * then this is definitely the last CSPLIT. -+ */ -+ *probably_last = 1; -+ } else { -+ /* Isoc IN. This is a bit risky if we are the first transaction: -+ * we may have been held off slightly. */ -+ if (i > 1 && st->dma_info.slot_len[st->dma_info.index-1] <= DATA0_PID_HEURISTIC) { -+ more_needed = 0; -+ } -+ /* If in the next uframe we will receive enough data to fill the endpoint, -+ * then only issue 1 more csplit. -+ */ -+ if (st->hctsiz_copy.b.xfersize - total_len <= DATA0_PID_HEURISTIC) -+ *probably_last = 1; -+ } -+ -+ if (total_len >= st->hctsiz_copy.b.xfersize || -+ i == 6 || total_len == 0) -+ /* Note: due to bit stuffing it is possible to have > 6 CSPLITs for -+ * a single endpoint. Accepting more would completely break our scheduling mechanism though -+ * - in these extreme cases we will pass through a truncated packet. -+ */ -+ more_needed = 0; -+ -+ return more_needed; -+} -+ -+/** -+ * fiq_fsm_too_late() - Test transaction for lateness -+ * -+ * If a SSPLIT for a large IN transaction is issued too late in a frame, -+ * the hub will disable the port to the device and respond with ERR handshakes. -+ * The hub status endpoint will not reflect this change. -+ * Returns 1 if we will issue a SSPLIT that will result in a device babble. -+ */ -+int notrace fiq_fsm_too_late(struct fiq_state *st, int n) -+{ -+ int uframe; -+ hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; -+ uframe = hfnum.b.frnum & 0x7; -+ if ((uframe < 6) && (st->channel[n].nrpackets + 1 + uframe > 7)) { -+ return 1; -+ } else { -+ return 0; -+ } -+} -+ -+ -+/** -+ * fiq_fsm_start_next_periodic() - A half-arsed attempt at a microframe pipeline -+ * -+ * Search pending transactions in the start-split pending state and queue them. -+ * Don't queue packets in uframe .5 (comes out in .6) (USB2.0 11.18.4). -+ * Note: we specifically don't do isochronous OUT transactions first because better -+ * use of the TT's start-split fifo can be achieved by pipelining an IN before an OUT. -+ */ -+static void notrace noinline fiq_fsm_start_next_periodic(struct fiq_state *st, int num_channels) -+{ -+ int n; -+ hfnum_data_t hfnum = { .d32 = FIQ_READ(st->dwc_regs_base + HFNUM) }; -+ if ((hfnum.b.frnum & 0x7) == 5) -+ return; -+ for (n = 0; n < num_channels; n++) { -+ if (st->channel[n].fsm == FIQ_PER_SSPLIT_QUEUED) { -+ /* Check to see if any other transactions are using this TT */ -+ if(!fiq_fsm_tt_in_use(st, num_channels, n)) { -+ if (!fiq_fsm_too_late(st, n)) { -+ st->channel[n].fsm = FIQ_PER_SSPLIT_STARTED; -+ fiq_print(FIQDBG_INT, st, "NEXTPER "); -+ fiq_fsm_restart_channel(st, n, 0); -+ } else { -+ st->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; -+ } -+ break; -+ } -+ } -+ } -+ for (n = 0; n < num_channels; n++) { -+ if (st->channel[n].fsm == FIQ_PER_ISO_OUT_PENDING) { -+ if (!fiq_fsm_tt_in_use(st, num_channels, n)) { -+ fiq_print(FIQDBG_INT, st, "NEXTISO "); -+ st->channel[n].fsm = FIQ_PER_ISO_OUT_ACTIVE; -+ fiq_fsm_restart_channel(st, n, 0); -+ break; -+ } -+ } -+ } -+} -+ -+/** -+ * fiq_fsm_update_hs_isoc() - update isochronous frame and transfer data -+ * @state: Pointer to fiq_state -+ * @n: Channel transaction is active on -+ * @hcint: Copy of host channel interrupt register -+ * -+ * Returns 0 if there are no more transactions for this HC to do, 1 -+ * otherwise. -+ */ -+static int notrace noinline fiq_fsm_update_hs_isoc(struct fiq_state *state, int n, hcint_data_t hcint) -+{ -+ struct fiq_channel_state *st = &state->channel[n]; -+ int xfer_len = 0, nrpackets = 0; -+ hcdma_data_t hcdma; -+ fiq_print(FIQDBG_INT, state, "HSISO %02d", n); -+ -+ xfer_len = fiq_get_xfer_len(state, n); -+ st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].actual_length = xfer_len; -+ -+ st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].status = hcint.d32; -+ -+ st->hs_isoc_info.index++; -+ if (st->hs_isoc_info.index == st->hs_isoc_info.nrframes) { -+ return 0; -+ } -+ -+ /* grab the next DMA address offset from the array */ -+ hcdma.d32 = st->hcdma_copy.d32 + st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].offset; -+ FIQ_WRITE(state->dwc_regs_base + HC_DMA + (HC_OFFSET * n), hcdma.d32); -+ -+ /* We need to set multi_count. This is a bit tricky - has to be set per-transaction as -+ * the core needs to be told to send the correct number. Caution: for IN transfers, -+ * this is always set to the maximum size of the endpoint. */ -+ xfer_len = st->hs_isoc_info.iso_desc[st->hs_isoc_info.index].length; -+ /* Integer divide in a FIQ: fun. FIXME: make this not suck */ -+ nrpackets = (xfer_len + st->hcchar_copy.b.mps - 1) / st->hcchar_copy.b.mps; -+ if (nrpackets == 0) -+ nrpackets = 1; -+ st->hcchar_copy.b.multicnt = nrpackets; -+ st->hctsiz_copy.b.pktcnt = nrpackets; -+ -+ /* Initial PID also needs to be set */ -+ if (st->hcchar_copy.b.epdir == 0) { -+ st->hctsiz_copy.b.xfersize = xfer_len; -+ switch (st->hcchar_copy.b.multicnt) { -+ case 1: -+ st->hctsiz_copy.b.pid = DWC_PID_DATA0; -+ break; -+ case 2: -+ case 3: -+ st->hctsiz_copy.b.pid = DWC_PID_MDATA; -+ break; -+ } -+ -+ } else { -+ switch (st->hcchar_copy.b.multicnt) { -+ st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps; -+ case 1: -+ st->hctsiz_copy.b.pid = DWC_PID_DATA0; -+ break; -+ case 2: -+ st->hctsiz_copy.b.pid = DWC_PID_DATA1; -+ break; -+ case 3: -+ st->hctsiz_copy.b.pid = DWC_PID_DATA2; -+ break; -+ } -+ } -+ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCTSIZ, st->hctsiz_copy.d32); -+ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR, st->hcchar_copy.d32); -+ /* Channel is enabled on hcint handler exit */ -+ fiq_print(FIQDBG_INT, state, "HSISOOUT"); -+ return 1; -+} -+ -+ -+/** -+ * fiq_fsm_do_sof() - FSM start-of-frame interrupt handler -+ * @state: Pointer to the state struct passed from banked FIQ mode registers. -+ * @num_channels: set according to the DWC hardware configuration -+ * -+ * The SOF handler in FSM mode has two functions -+ * 1. Hold off SOF from causing schedule advancement in IRQ context if there's -+ * nothing to do -+ * 2. Advance certain FSM states that require either a microframe delay, or a microframe -+ * of holdoff. -+ * -+ * The second part is architecture-specific to mach-bcm2835 - -+ * a sane interrupt controller would have a mask register for ARM interrupt sources -+ * to be promoted to the nFIQ line, but it doesn't. Instead a single interrupt -+ * number (USB) can be enabled. This means that certain parts of the USB specification -+ * that require "wait a little while, then issue another packet" cannot be fulfilled with -+ * the timing granularity required to achieve optimal throughout. The workaround is to use -+ * the SOF "timer" (125uS) to perform this task. -+ */ -+static int notrace noinline fiq_fsm_do_sof(struct fiq_state *state, int num_channels) -+{ -+ hfnum_data_t hfnum = { .d32 = FIQ_READ(state->dwc_regs_base + HFNUM) }; -+ int n; -+ int kick_irq = 0; -+ -+ if ((hfnum.b.frnum & 0x7) == 1) { -+ /* We cannot issue csplits for transactions in the last frame past (n+1).1 -+ * Check to see if there are any transactions that are stale. -+ * Boot them out. -+ */ -+ for (n = 0; n < num_channels; n++) { -+ switch (state->channel[n].fsm) { -+ case FIQ_PER_CSPLIT_WAIT: -+ case FIQ_PER_CSPLIT_NYET1: -+ case FIQ_PER_CSPLIT_POLL: -+ case FIQ_PER_CSPLIT_LAST: -+ /* Check if we are no longer in the same full-speed frame. */ -+ if (((state->channel[n].expected_uframe & 0x3FFF) & ~0x7) < -+ (hfnum.b.frnum & ~0x7)) -+ state->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; -+ break; -+ default: -+ break; -+ } -+ } -+ } -+ -+ for (n = 0; n < num_channels; n++) { -+ switch (state->channel[n].fsm) { -+ -+ case FIQ_NP_SSPLIT_RETRY: -+ case FIQ_NP_IN_CSPLIT_RETRY: -+ case FIQ_NP_OUT_CSPLIT_RETRY: -+ fiq_fsm_restart_channel(state, n, 0); -+ break; -+ -+ case FIQ_HS_ISOC_SLEEPING: -+ state->channel[n].fsm = FIQ_HS_ISOC_TURBO; -+ fiq_fsm_restart_channel(state, n, 0); -+ break; -+ -+ case FIQ_PER_SSPLIT_QUEUED: -+ if ((hfnum.b.frnum & 0x7) == 5) -+ break; -+ if(!fiq_fsm_tt_in_use(state, num_channels, n)) { -+ if (!fiq_fsm_too_late(state, n)) { -+ fiq_print(FIQDBG_INT, st, "SOF GO %01d", n); -+ fiq_fsm_restart_channel(state, n, 0); -+ state->channel[n].fsm = FIQ_PER_SSPLIT_STARTED; -+ } else { -+ /* Transaction cannot be started without risking a device babble error */ -+ state->channel[n].fsm = FIQ_PER_SPLIT_TIMEOUT; -+ state->haintmsk_saved.b2.chint &= ~(1 << n); -+ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, 0); -+ kick_irq |= 1; -+ } -+ } -+ break; -+ -+ case FIQ_PER_ISO_OUT_PENDING: -+ /* Ordinarily, this should be poked after the SSPLIT -+ * complete interrupt for a competing transfer on the same -+ * TT. Doesn't happen for aborted transactions though. -+ */ -+ if ((hfnum.b.frnum & 0x7) >= 5) -+ break; -+ if (!fiq_fsm_tt_in_use(state, num_channels, n)) { -+ /* Hardware bug. SOF can sometimes occur after the channel halt interrupt -+ * that caused this. -+ */ -+ fiq_fsm_restart_channel(state, n, 0); -+ fiq_print(FIQDBG_INT, state, "SOF ISOC"); -+ if (state->channel[n].nrpackets == 1) { -+ state->channel[n].fsm = FIQ_PER_ISO_OUT_LAST; -+ } else { -+ state->channel[n].fsm = FIQ_PER_ISO_OUT_ACTIVE; -+ } -+ } -+ break; -+ -+ case FIQ_PER_CSPLIT_WAIT: -+ /* we are guaranteed to be in this state if and only if the SSPLIT interrupt -+ * occurred when the bus transaction occurred. The SOF interrupt reversal bug -+ * will utterly bugger this up though. -+ */ -+ if (hfnum.b.frnum != state->channel[n].expected_uframe) { -+ fiq_print(FIQDBG_INT, state, "SOFCS %d ", n); -+ state->channel[n].fsm = FIQ_PER_CSPLIT_POLL; -+ fiq_fsm_restart_channel(state, n, 0); -+ fiq_fsm_start_next_periodic(state, num_channels); -+ -+ } -+ break; -+ -+ case FIQ_PER_SPLIT_TIMEOUT: -+ /* Ugly: we have to force a HCD interrupt. -+ * Poke the mask for the channel in question. -+ * We will take a fake SOF because of this, but -+ * that's OK. -+ */ -+ state->haintmsk_saved.b2.chint &= ~(1 << n); -+ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, 0); -+ kick_irq |= 1; -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ if (state->kick_np_queues || -+ dwc_frame_num_le(state->next_sched_frame, hfnum.b.frnum)) -+ kick_irq |= 1; -+ -+ return !kick_irq; -+} -+ -+ -+/** -+ * fiq_fsm_do_hcintr() - FSM host channel interrupt handler -+ * @state: Pointer to the FIQ state struct -+ * @num_channels: Number of channels as per hardware config -+ * @n: channel for which HAINT(i) was raised -+ * -+ * An important property is that only the CHHLT interrupt is unmasked. Unfortunately, AHBerr is as well. -+ */ -+static int notrace noinline fiq_fsm_do_hcintr(struct fiq_state *state, int num_channels, int n) -+{ -+ hcint_data_t hcint; -+ hcintmsk_data_t hcintmsk; -+ hcint_data_t hcint_probe; -+ hcchar_data_t hcchar; -+ int handled = 0; -+ int restart = 0; -+ int last_csplit = 0; -+ int start_next_periodic = 0; -+ struct fiq_channel_state *st = &state->channel[n]; -+ hfnum_data_t hfnum; -+ -+ hcint.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINT); -+ hcintmsk.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK); -+ hcint_probe.d32 = hcint.d32 & hcintmsk.d32; -+ -+ if (st->fsm != FIQ_PASSTHROUGH) { -+ fiq_print(FIQDBG_INT, state, "HC%01d ST%02d", n, st->fsm); -+ fiq_print(FIQDBG_INT, state, "%08x", hcint.d32); -+ } -+ -+ switch (st->fsm) { -+ -+ case FIQ_PASSTHROUGH: -+ case FIQ_DEQUEUE_ISSUED: -+ /* doesn't belong to us, kick it upstairs */ -+ break; -+ -+ case FIQ_PASSTHROUGH_ERRORSTATE: -+ /* We are here to emulate the error recovery mechanism of the dwc HCD. -+ * Several interrupts are unmasked if a previous transaction failed - it's -+ * death for the FIQ to attempt to handle them as the channel isn't halted. -+ * Emulate what the HCD does in this situation: mask and continue. -+ * The FSM has no other state setup so this has to be handled out-of-band. -+ */ -+ fiq_print(FIQDBG_ERR, state, "ERRST %02d", n); -+ if (hcint_probe.b.nak || hcint_probe.b.ack || hcint_probe.b.datatglerr) { -+ fiq_print(FIQDBG_ERR, state, "RESET %02d", n); -+ st->nr_errors = 0; -+ hcintmsk.b.nak = 0; -+ hcintmsk.b.ack = 0; -+ hcintmsk.b.datatglerr = 0; -+ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINTMSK, hcintmsk.d32); -+ return 1; -+ } -+ if (hcint_probe.b.chhltd) { -+ fiq_print(FIQDBG_ERR, state, "CHHLT %02d", n); -+ fiq_print(FIQDBG_ERR, state, "%08x", hcint.d32); -+ return 0; -+ } -+ break; -+ -+ /* Non-periodic state groups */ -+ case FIQ_NP_SSPLIT_STARTED: -+ case FIQ_NP_SSPLIT_RETRY: -+ /* Got a HCINT for a NP SSPLIT. Expected ACK / NAK / fail */ -+ if (hcint.b.ack) { -+ /* SSPLIT complete. For OUT, the data has been sent. For IN, the LS transaction -+ * will start shortly. SOF needs to kick the transaction to prevent a NYET flood. -+ */ -+ if(st->hcchar_copy.b.epdir == 1) -+ st->fsm = FIQ_NP_IN_CSPLIT_RETRY; -+ else -+ st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; -+ st->nr_errors = 0; -+ handled = 1; -+ fiq_fsm_setup_csplit(state, n); -+ } else if (hcint.b.nak) { -+ // No buffer space in TT. Retry on a uframe boundary. -+ st->fsm = FIQ_NP_SSPLIT_RETRY; -+ handled = 1; -+ } else if (hcint.b.xacterr) { -+ // The only other one we care about is xacterr. This implies HS bus error - retry. -+ st->nr_errors++; -+ st->fsm = FIQ_NP_SSPLIT_RETRY; -+ if (st->nr_errors >= 3) { -+ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; -+ } else { -+ handled = 1; -+ restart = 1; -+ } -+ } else { -+ st->fsm = FIQ_NP_SPLIT_LS_ABORTED; -+ handled = 0; -+ restart = 0; -+ } -+ break; -+ -+ case FIQ_NP_IN_CSPLIT_RETRY: -+ /* Received a CSPLIT done interrupt. -+ * Expected Data/NAK/STALL/NYET for IN. -+ */ -+ if (hcint.b.xfercomp) { -+ /* For IN, data is present. */ -+ st->fsm = FIQ_NP_SPLIT_DONE; -+ } else if (hcint.b.nak) { -+ /* no endpoint data. Punt it upstairs */ -+ st->fsm = FIQ_NP_SPLIT_DONE; -+ } else if (hcint.b.nyet) { -+ /* CSPLIT NYET - retry on a uframe boundary. */ -+ handled = 1; -+ st->nr_errors = 0; -+ } else if (hcint.b.datatglerr) { -+ /* data toggle errors do not set the xfercomp bit. */ -+ st->fsm = FIQ_NP_SPLIT_LS_ABORTED; -+ } else if (hcint.b.xacterr) { -+ /* HS error. Retry immediate */ -+ st->fsm = FIQ_NP_IN_CSPLIT_RETRY; -+ st->nr_errors++; -+ if (st->nr_errors >= 3) { -+ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; -+ } else { -+ handled = 1; -+ restart = 1; -+ } -+ } else if (hcint.b.stall) { -+ /* A STALL implies either a LS bus error or a genuine STALL. */ -+ st->fsm = FIQ_NP_SPLIT_LS_ABORTED; -+ } else { -+ /* Hardware bug. It's possible in some cases to -+ * get a channel halt with nothing else set when -+ * the response was a NYET. Treat as local 3-strikes retry. -+ */ -+ hcint_data_t hcint_test = hcint; -+ hcint_test.b.chhltd = 0; -+ if (!hcint_test.d32) { -+ st->nr_errors++; -+ if (st->nr_errors >= 3) { -+ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; -+ } else { -+ handled = 1; -+ } -+ } else { -+ /* Bail out if something unexpected happened */ -+ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; -+ } -+ } -+ break; -+ -+ case FIQ_NP_OUT_CSPLIT_RETRY: -+ /* Received a CSPLIT done interrupt. -+ * Expected ACK/NAK/STALL/NYET/XFERCOMP for OUT.*/ -+ if (hcint.b.xfercomp) { -+ st->fsm = FIQ_NP_SPLIT_DONE; -+ } else if (hcint.b.nak) { -+ // The HCD will implement the holdoff on frame boundaries. -+ st->fsm = FIQ_NP_SPLIT_DONE; -+ } else if (hcint.b.nyet) { -+ // Hub still processing. -+ st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; -+ handled = 1; -+ st->nr_errors = 0; -+ //restart = 1; -+ } else if (hcint.b.xacterr) { -+ /* HS error. retry immediate */ -+ st->fsm = FIQ_NP_OUT_CSPLIT_RETRY; -+ st->nr_errors++; -+ if (st->nr_errors >= 3) { -+ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; -+ } else { -+ handled = 1; -+ restart = 1; -+ } -+ } else if (hcint.b.stall) { -+ /* LS bus error or genuine stall */ -+ st->fsm = FIQ_NP_SPLIT_LS_ABORTED; -+ } else { -+ /* -+ * Hardware bug. It's possible in some cases to get a -+ * channel halt with nothing else set when the response was a NYET. -+ * Treat as local 3-strikes retry. -+ */ -+ hcint_data_t hcint_test = hcint; -+ hcint_test.b.chhltd = 0; -+ if (!hcint_test.d32) { -+ st->nr_errors++; -+ if (st->nr_errors >= 3) { -+ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; -+ } else { -+ handled = 1; -+ } -+ } else { -+ // Something unexpected happened. AHBerror or babble perhaps. Let the IRQ deal with it. -+ st->fsm = FIQ_NP_SPLIT_HS_ABORTED; -+ } -+ } -+ break; -+ -+ /* Periodic split states (except isoc out) */ -+ case FIQ_PER_SSPLIT_STARTED: -+ /* Expect an ACK or failure for SSPLIT */ -+ if (hcint.b.ack) { -+ /* -+ * SSPLIT transfer complete interrupt - the generation of this interrupt is fraught with bugs. -+ * For a packet queued in microframe n-3 to appear in n-2, if the channel is enabled near the EOF1 -+ * point for microframe n-3, the packet will not appear on the bus until microframe n. -+ * Additionally, the generation of the actual interrupt is dodgy. For a packet appearing on the bus -+ * in microframe n, sometimes the interrupt is generated immediately. Sometimes, it appears in n+1 -+ * coincident with SOF for n+1. -+ * SOF is also buggy. It can sometimes be raised AFTER the first bus transaction has taken place. -+ * These appear to be caused by timing/clock crossing bugs within the core itself. -+ * State machine workaround. -+ */ -+ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); -+ hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); -+ fiq_fsm_setup_csplit(state, n); -+ /* Poke the oddfrm bit. If we are equivalent, we received the interrupt at the correct -+ * time. If not, then we're in the next SOF. -+ */ -+ if ((hfnum.b.frnum & 0x1) == hcchar.b.oddfrm) { -+ fiq_print(FIQDBG_INT, state, "CSWAIT %01d", n); -+ st->expected_uframe = hfnum.b.frnum; -+ st->fsm = FIQ_PER_CSPLIT_WAIT; -+ } else { -+ fiq_print(FIQDBG_INT, state, "CSPOL %01d", n); -+ /* For isochronous IN endpoints, -+ * we need to hold off if we are expecting a lot of data */ -+ if (st->hcchar_copy.b.mps < DATA0_PID_HEURISTIC) { -+ start_next_periodic = 1; -+ } -+ /* Danger will robinson: we are in a broken state. If our first interrupt after -+ * this is a NYET, it will be delayed by 1 uframe and result in an unrecoverable -+ * lag. Unmask the NYET interrupt. -+ */ -+ st->expected_uframe = (hfnum.b.frnum + 1) & 0x3FFF; -+ st->fsm = FIQ_PER_CSPLIT_BROKEN_NYET1; -+ restart = 1; -+ } -+ handled = 1; -+ } else if (hcint.b.xacterr) { -+ /* 3-strikes retry is enabled, we have hit our max nr_errors */ -+ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; -+ start_next_periodic = 1; -+ } else { -+ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; -+ start_next_periodic = 1; -+ } -+ /* We can now queue the next isochronous OUT transaction, if one is pending. */ -+ if(fiq_fsm_tt_next_isoc(state, num_channels, n)) { -+ fiq_print(FIQDBG_INT, state, "NEXTISO "); -+ } -+ break; -+ -+ case FIQ_PER_CSPLIT_NYET1: -+ /* First CSPLIT attempt was a NYET. If we get a subsequent NYET, -+ * we are too late and the TT has dropped its CSPLIT fifo. -+ */ -+ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); -+ hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); -+ start_next_periodic = 1; -+ if (hcint.b.nak) { -+ st->fsm = FIQ_PER_SPLIT_DONE; -+ } else if (hcint.b.xfercomp) { -+ fiq_increment_dma_buf(state, num_channels, n); -+ st->fsm = FIQ_PER_CSPLIT_POLL; -+ st->nr_errors = 0; -+ if (fiq_fsm_more_csplits(state, n, &last_csplit)) { -+ handled = 1; -+ restart = 1; -+ if (!last_csplit) -+ start_next_periodic = 0; -+ } else { -+ st->fsm = FIQ_PER_SPLIT_DONE; -+ } -+ } else if (hcint.b.nyet) { -+ /* Doh. Data lost. */ -+ st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; -+ } else if (hcint.b.xacterr || hcint.b.stall) { -+ st->fsm = FIQ_PER_SPLIT_LS_ABORTED; -+ } else { -+ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; -+ } -+ break; -+ -+ case FIQ_PER_CSPLIT_BROKEN_NYET1: -+ /* -+ * we got here because our host channel is in the delayed-interrupt -+ * state and we cannot take a NYET interrupt any later than when it -+ * occurred. Disable then re-enable the channel if this happens to force -+ * CSPLITs to occur at the right time. -+ */ -+ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); -+ hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); -+ fiq_print(FIQDBG_INT, state, "BROK: %01d ", n); -+ if (hcint.b.nak) { -+ st->fsm = FIQ_PER_SPLIT_DONE; -+ start_next_periodic = 1; -+ } else if (hcint.b.xfercomp) { -+ fiq_increment_dma_buf(state, num_channels, n); -+ if (fiq_fsm_more_csplits(state, n, &last_csplit)) { -+ st->fsm = FIQ_PER_CSPLIT_POLL; -+ handled = 1; -+ restart = 1; -+ start_next_periodic = 1; -+ /* Reload HCTSIZ for the next transfer */ -+ fiq_fsm_reload_hctsiz(state, n); -+ if (!last_csplit) -+ start_next_periodic = 0; -+ } else { -+ st->fsm = FIQ_PER_SPLIT_DONE; -+ } -+ } else if (hcint.b.nyet) { -+ st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; -+ start_next_periodic = 1; -+ } else if (hcint.b.xacterr) { -+ /* Local 3-strikes retry is handled by the core. This is a ERR response.*/ -+ st->fsm = FIQ_PER_SPLIT_LS_ABORTED; -+ } else { -+ fiq_print(FIQDBG_INT, state, "TOGGLES"); -+ BUG(); -+ } -+ break; -+ -+ case FIQ_PER_CSPLIT_POLL: -+ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); -+ hcchar.d32 = FIQ_READ(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCCHAR); -+ start_next_periodic = 1; -+ if (hcint.b.nak) { -+ st->fsm = FIQ_PER_SPLIT_DONE; -+ } else if (hcint.b.xfercomp) { -+ fiq_increment_dma_buf(state, num_channels, n); -+ if (fiq_fsm_more_csplits(state, n, &last_csplit)) { -+ handled = 1; -+ restart = 1; -+ /* Reload HCTSIZ for the next transfer */ -+ fiq_fsm_reload_hctsiz(state, n); -+ if (!last_csplit) -+ start_next_periodic = 0; -+ } else { -+ st->fsm = FIQ_PER_SPLIT_DONE; -+ } -+ } else if (hcint.b.nyet) { -+ /* Are we a NYET after the first data packet? */ -+ if (st->nrpackets == 0) { -+ st->fsm = FIQ_PER_CSPLIT_NYET1; -+ handled = 1; -+ restart = 1; -+ } else { -+ /* We got a NYET when polling CSPLITs. Can happen -+ * if our heuristic fails, or if someone disables us -+ * for any significant length of time. -+ */ -+ if (st->nr_errors >= 3) { -+ st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; -+ } else { -+ st->fsm = FIQ_PER_SPLIT_DONE; -+ } -+ } -+ } else if (hcint.b.xacterr || hcint.b.stall) { -+ /* For xacterr, Local 3-strikes retry is handled by the core. This is a ERR response.*/ -+ st->fsm = FIQ_PER_SPLIT_LS_ABORTED; -+ } else if (hcint.b.datatglerr) { -+ fiq_print(FIQDBG_INT, state, "TOGGLES"); -+ BUG(); -+ } else { -+ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; -+ } -+ break; -+ -+ case FIQ_HS_ISOC_TURBO: -+ if (fiq_fsm_update_hs_isoc(state, n, hcint)) { -+ /* more transactions to come */ -+ handled = 1; -+ restart = 1; -+ fiq_print(FIQDBG_INT, state, "HSISO M "); -+ } else { -+ st->fsm = FIQ_HS_ISOC_DONE; -+ fiq_print(FIQDBG_INT, state, "HSISO F "); -+ } -+ break; -+ -+ case FIQ_HS_ISOC_ABORTED: -+ /* This abort is called by the driver rewriting the state mid-transaction -+ * which allows the dequeue mechanism to work more effectively. -+ */ -+ break; -+ -+ case FIQ_PER_ISO_OUT_ACTIVE: -+ if (hcint.b.ack) { -+ if(fiq_iso_out_advance(state, num_channels, n)) { -+ /* last OUT transfer */ -+ st->fsm = FIQ_PER_ISO_OUT_LAST; -+ /* -+ * Assuming the periodic FIFO in the dwc core -+ * actually does its job properly, we can queue -+ * the next ssplit now and in theory, the wire -+ * transactions will be in-order. -+ */ -+ // No it doesn't. It appears to process requests in host channel order. -+ //start_next_periodic = 1; -+ } -+ handled = 1; -+ restart = 1; -+ } else { -+ /* -+ * Isochronous transactions carry on regardless. Log the error -+ * and continue. -+ */ -+ //explode += 1; -+ st->nr_errors++; -+ if(fiq_iso_out_advance(state, num_channels, n)) { -+ st->fsm = FIQ_PER_ISO_OUT_LAST; -+ //start_next_periodic = 1; -+ } -+ handled = 1; -+ restart = 1; -+ } -+ break; -+ -+ case FIQ_PER_ISO_OUT_LAST: -+ if (hcint.b.ack) { -+ /* All done here */ -+ st->fsm = FIQ_PER_ISO_OUT_DONE; -+ } else { -+ st->fsm = FIQ_PER_ISO_OUT_DONE; -+ st->nr_errors++; -+ } -+ start_next_periodic = 1; -+ break; -+ -+ case FIQ_PER_SPLIT_TIMEOUT: -+ /* SOF kicked us because we overran. */ -+ start_next_periodic = 1; -+ break; -+ -+ default: -+ break; -+ } -+ -+ if (handled) { -+ FIQ_WRITE(state->dwc_regs_base + HC_START + (HC_OFFSET * n) + HCINT, hcint.d32); -+ } else { -+ /* Copy the regs into the state so the IRQ knows what to do */ -+ st->hcint_copy.d32 = hcint.d32; -+ } -+ -+ if (restart) { -+ /* Restart always implies handled. */ -+ if (restart == 2) { -+ /* For complete-split INs, the show must go on. -+ * Force a channel restart */ -+ fiq_fsm_restart_channel(state, n, 1); -+ } else { -+ fiq_fsm_restart_channel(state, n, 0); -+ } -+ } -+ if (start_next_periodic) { -+ fiq_fsm_start_next_periodic(state, num_channels); -+ } -+ if (st->fsm != FIQ_PASSTHROUGH) -+ fiq_print(FIQDBG_INT, state, "FSMOUT%02d", st->fsm); -+ -+ return handled; -+} -+ -+ -+/** -+ * dwc_otg_fiq_fsm() - Flying State Machine (monster) FIQ -+ * @state: pointer to state struct passed from the banked FIQ mode registers. -+ * @num_channels: set according to the DWC hardware configuration -+ * @dma: pointer to DMA bounce buffers for split transaction slots -+ * -+ * The FSM FIQ performs the low-level tasks that normally would be performed by the microcode -+ * inside an EHCI or similar host controller regarding split transactions. The DWC core -+ * interrupts each and every time a split transaction packet is received or sent successfully. -+ * This results in either an interrupt storm when everything is working "properly", or -+ * the interrupt latency of the system in general breaks time-sensitive periodic split -+ * transactions. Pushing the low-level, but relatively easy state machine work into the FIQ -+ * solves these problems. -+ * -+ * Return: void -+ */ -+void notrace dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels) -+{ -+ gintsts_data_t gintsts, gintsts_handled; -+ gintmsk_data_t gintmsk; -+ //hfnum_data_t hfnum; -+ haint_data_t haint, haint_handled; -+ haintmsk_data_t haintmsk; -+ int kick_irq = 0; -+ -+ gintsts_handled.d32 = 0; -+ haint_handled.d32 = 0; -+ -+ gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS); -+ gintmsk.d32 = FIQ_READ(state->dwc_regs_base + GINTMSK); -+ gintsts.d32 &= gintmsk.d32; -+ -+ if (gintsts.b.sofintr) { -+ /* For FSM mode, SOF is required to keep the state machine advance for -+ * certain stages of the periodic pipeline. It's death to mask this -+ * interrupt in that case. -+ */ -+ -+ if (!fiq_fsm_do_sof(state, num_channels)) { -+ /* Kick IRQ once. Queue advancement means that all pending transactions -+ * will get serviced when the IRQ finally executes. -+ */ -+ if (state->gintmsk_saved.b.sofintr == 1) -+ kick_irq |= 1; -+ state->gintmsk_saved.b.sofintr = 0; -+ } -+ gintsts_handled.b.sofintr = 1; -+ } -+ -+ if (gintsts.b.hcintr) { -+ int i; -+ haint.d32 = FIQ_READ(state->dwc_regs_base + HAINT); -+ haintmsk.d32 = FIQ_READ(state->dwc_regs_base + HAINTMSK); -+ haint.d32 &= haintmsk.d32; -+ haint_handled.d32 = 0; -+ for (i=0; ihaintmsk_saved.b2.chint &= ~(1 << i); -+ } else { -+ /* do_hcintr cleaned up after itself, but clear haint */ -+ haint_handled.b2.chint |= (1 << i); -+ } -+ } -+ } -+ -+ if (haint_handled.b2.chint) { -+ FIQ_WRITE(state->dwc_regs_base + HAINT, haint_handled.d32); -+ } -+ -+ if (haintmsk.d32 != (haintmsk.d32 & state->haintmsk_saved.d32)) { -+ /* -+ * This is necessary to avoid multiple retriggers of the MPHI in the case -+ * where interrupts are held off and HCINTs start to pile up. -+ * Only wake up the IRQ if a new interrupt came in, was not handled and was -+ * masked. -+ */ -+ haintmsk.d32 &= state->haintmsk_saved.d32; -+ FIQ_WRITE(state->dwc_regs_base + HAINTMSK, haintmsk.d32); -+ kick_irq |= 1; -+ } -+ /* Top-Level interrupt - always handled because it's level-sensitive */ -+ gintsts_handled.b.hcintr = 1; -+ } -+ -+ -+ /* Clear the bits in the saved register that were not handled but were triggered. */ -+ state->gintmsk_saved.d32 &= ~(gintsts.d32 & ~gintsts_handled.d32); -+ -+ /* FIQ didn't handle something - mask has changed - write new mask */ -+ if (gintmsk.d32 != (gintmsk.d32 & state->gintmsk_saved.d32)) { -+ gintmsk.d32 &= state->gintmsk_saved.d32; -+ gintmsk.b.sofintr = 1; -+ FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32); -+// fiq_print(FIQDBG_INT, state, "KICKGINT"); -+// fiq_print(FIQDBG_INT, state, "%08x", gintmsk.d32); -+// fiq_print(FIQDBG_INT, state, "%08x", state->gintmsk_saved.d32); -+ kick_irq |= 1; -+ } -+ -+ if (gintsts_handled.d32) { -+ /* Only applies to edge-sensitive bits in GINTSTS */ -+ FIQ_WRITE(state->dwc_regs_base + GINTSTS, gintsts_handled.d32); -+ } -+ -+ /* We got an interrupt, didn't handle it. */ -+ if (kick_irq) { -+ state->mphi_int_count++; -+ FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send); -+ FIQ_WRITE(state->mphi_regs.outddb, (1<<29)); -+ -+ } -+ state->fiq_done++; -+ mb(); -+} -+ -+ -+/** -+ * dwc_otg_fiq_nop() - FIQ "lite" -+ * @state: pointer to state struct passed from the banked FIQ mode registers. -+ * -+ * The "nop" handler does not intervene on any interrupts other than SOF. -+ * It is limited in scope to deciding at each SOF if the IRQ SOF handler (which deals -+ * with non-periodic/periodic queues) needs to be kicked. -+ * -+ * This is done to hold off the SOF interrupt, which occurs at a rate of 8000 per second. -+ * -+ * Return: void -+ */ -+void notrace dwc_otg_fiq_nop(struct fiq_state *state) -+{ -+ gintsts_data_t gintsts, gintsts_handled; -+ gintmsk_data_t gintmsk; -+ hfnum_data_t hfnum; -+ -+ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); -+ gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS); -+ gintmsk.d32 = FIQ_READ(state->dwc_regs_base + GINTMSK); -+ gintsts.d32 &= gintmsk.d32; -+ gintsts_handled.d32 = 0; -+ -+ if (gintsts.b.sofintr) { -+ if (!state->kick_np_queues && -+ dwc_frame_num_gt(state->next_sched_frame, hfnum.b.frnum)) { -+ /* SOF handled, no work to do, just ACK interrupt */ -+ gintsts_handled.b.sofintr = 1; -+ } else { -+ /* Kick IRQ */ -+ state->gintmsk_saved.b.sofintr = 0; -+ } -+ } -+ -+ /* Reset handled interrupts */ -+ if(gintsts_handled.d32) { -+ FIQ_WRITE(state->dwc_regs_base + GINTSTS, gintsts_handled.d32); -+ } -+ -+ /* Clear the bits in the saved register that were not handled but were triggered. */ -+ state->gintmsk_saved.d32 &= ~(gintsts.d32 & ~gintsts_handled.d32); -+ -+ /* We got an interrupt, didn't handle it and want to mask it */ -+ if (~(state->gintmsk_saved.d32)) { -+ state->mphi_int_count++; -+ gintmsk.d32 &= state->gintmsk_saved.d32; -+ FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32); -+ /* Force a clear before another dummy send */ -+ FIQ_WRITE(state->mphi_regs.intstat, (1<<29)); -+ FIQ_WRITE(state->mphi_regs.outdda, (int) state->dummy_send); -+ FIQ_WRITE(state->mphi_regs.outddb, (1<<29)); -+ -+ } -+ state->fiq_done++; -+ mb(); -+} -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h -new file mode 100644 -index 0000000..7572958 ---- /dev/null -+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h -@@ -0,0 +1,353 @@ -+/* -+ * dwc_otg_fiq_fsm.h - Finite state machine FIQ header definitions -+ * -+ * Copyright (c) 2013 Raspberry Pi Foundation -+ * -+ * Author: Jonathan Bell -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * * Neither the name of Raspberry Pi nor the -+ * names of its contributors may be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This FIQ implements functionality that performs split transactions on -+ * the dwc_otg hardware without any outside intervention. A split transaction -+ * is "queued" by nominating a specific host channel to perform the entirety -+ * of a split transaction. This FIQ will then perform the microframe-precise -+ * scheduling required in each phase of the transaction until completion. -+ * -+ * The FIQ functionality has been surgically implanted into the Synopsys -+ * vendor-provided driver. -+ * -+ */ -+ -+#ifndef DWC_OTG_FIQ_FSM_H_ -+#define DWC_OTG_FIQ_FSM_H_ -+ -+#include "dwc_otg_regs.h" -+#include "dwc_otg_cil.h" -+#include "dwc_otg_hcd.h" -+#include -+#include -+#include -+#include -+ -+#if 0 -+#define FLAME_ON(x) \ -+do { \ -+ int gpioreg; \ -+ \ -+ gpioreg = readl(__io_address(0x20200000+0x8)); \ -+ gpioreg &= ~(7 << (x-20)*3); \ -+ gpioreg |= 0x1 << (x-20)*3; \ -+ writel(gpioreg, __io_address(0x20200000+0x8)); \ -+ \ -+ writel(1< 1, SOF wakes up the isochronous FSM */ -+ FIQ_HS_ISOC_SLEEPING = 24, -+ FIQ_HS_ISOC_DONE = 25, -+ FIQ_HS_ISOC_ABORTED = 26, -+ FIQ_DEQUEUE_ISSUED = 30, -+ FIQ_TEST = 32, -+}; -+ -+struct fiq_stack { -+ int magic1; -+ uint8_t stack[2048]; -+ int magic2; -+}; -+ -+ -+/** -+ * struct fiq_dma_info - DMA bounce buffer utilisation information (per-channel) -+ * @index: Number of slots reported used for IN transactions / number of slots -+ * transmitted for an OUT transaction -+ * @slot_len[6]: Number of actual transfer bytes in each slot (255 if unused) -+ * -+ * Split transaction transfers can have variable length depending on other bus -+ * traffic. The OTG core DMA engine requires 4-byte aligned addresses therefore -+ * each transaction needs a guaranteed aligned address. A maximum of 6 split transfers -+ * can happen per-frame. -+ */ -+struct fiq_dma_info { -+ u8 index; -+ u8 slot_len[6]; -+}; -+ -+struct __attribute__((packed)) fiq_split_dma_slot { -+ u8 buf[188]; -+}; -+ -+struct fiq_dma_channel { -+ struct __attribute__((packed)) fiq_split_dma_slot index[6]; -+}; -+ -+struct fiq_dma_blob { -+ struct __attribute__((packed)) fiq_dma_channel channel[0]; -+}; -+ -+/** -+ * struct fiq_hs_isoc_info - USB2.0 isochronous data -+ * @iso_frame: Pointer to the array of OTG URB iso_frame_descs. -+ * @nrframes: Total length of iso_frame_desc array -+ * @index: Current index (FIQ-maintained) -+ * -+ */ -+struct fiq_hs_isoc_info { -+ struct dwc_otg_hcd_iso_packet_desc *iso_desc; -+ unsigned int nrframes; -+ unsigned int index; -+}; -+ -+/** -+ * struct fiq_channel_state - FIQ state machine storage -+ * @fsm: Current state of the channel as understood by the FIQ -+ * @nr_errors: Number of transaction errors on this split-transaction -+ * @hub_addr: SSPLIT/CSPLIT destination hub -+ * @port_addr: SSPLIT/CSPLIT destination port - always 1 if single TT hub -+ * @nrpackets: For isoc OUT, the number of split-OUT packets to transmit. For -+ * split-IN, number of CSPLIT data packets that were received. -+ * @hcchar_copy: -+ * @hcsplt_copy: -+ * @hcintmsk_copy: -+ * @hctsiz_copy: Copies of the host channel registers. -+ * For use as scratch, or for returning state. -+ * -+ * The fiq_channel_state is state storage between interrupts for a host channel. The -+ * FSM state is stored here. Members of this structure must only be set up by the -+ * driver prior to enabling the FIQ for this host channel, and not touched until the FIQ -+ * has updated the state to either a COMPLETE state group or ABORT state group. -+ */ -+ -+struct fiq_channel_state { -+ enum fiq_fsm_state fsm; -+ unsigned int nr_errors; -+ unsigned int hub_addr; -+ unsigned int port_addr; -+ /* Hardware bug workaround: sometimes channel halt interrupts are -+ * delayed until the next SOF. Keep track of when we expected to get interrupted. */ -+ unsigned int expected_uframe; -+ /* in/out for communicating number of dma buffers used, or number of ISOC to do */ -+ unsigned int nrpackets; -+ struct fiq_dma_info dma_info; -+ struct fiq_hs_isoc_info hs_isoc_info; -+ /* Copies of HC registers - in/out communication from/to IRQ handler -+ * and for ease of channel setup. A bit of mungeing is performed - for -+ * example the hctsiz.b.maxp is _always_ the max packet size of the endpoint. -+ */ -+ hcchar_data_t hcchar_copy; -+ hcsplt_data_t hcsplt_copy; -+ hcint_data_t hcint_copy; -+ hcintmsk_data_t hcintmsk_copy; -+ hctsiz_data_t hctsiz_copy; -+ hcdma_data_t hcdma_copy; -+}; -+ -+/** -+ * struct fiq_state - top-level FIQ state machine storage -+ * @mphi_regs: virtual address of the MPHI peripheral register file -+ * @dwc_regs_base: virtual address of the base of the DWC core register file -+ * @dma_base: physical address for the base of the DMA bounce buffers -+ * @dummy_send: Scratch area for sending a fake message to the MPHI peripheral -+ * @gintmsk_saved: Top-level mask of interrupts that the FIQ has not handled. -+ * Used for determining which interrupts fired to set off the IRQ handler. -+ * @haintmsk_saved: Mask of interrupts from host channels that the FIQ did not handle internally. -+ * @np_count: Non-periodic transactions in the active queue -+ * @np_sent: Count of non-periodic transactions that have completed -+ * @next_sched_frame: For periodic transactions handled by the driver's SOF-driven queuing mechanism, -+ * this is the next frame on which a SOF interrupt is required. Used to hold off -+ * passing SOF through to the driver until necessary. -+ * @channel[n]: Per-channel FIQ state. Allocated during init depending on the number of host -+ * channels configured into the core logic. -+ * -+ * This is passed as the first argument to the dwc_otg_fiq_fsm top-level FIQ handler from the asm stub. -+ * It contains top-level state information. -+ */ -+struct fiq_state { -+ mphi_regs_t mphi_regs; -+ void *dwc_regs_base; -+ dma_addr_t dma_base; -+ struct fiq_dma_blob *fiq_dmab; -+ void *dummy_send; -+ gintmsk_data_t gintmsk_saved; -+ haintmsk_data_t haintmsk_saved; -+ int mphi_int_count; -+ unsigned int fiq_done; -+ unsigned int kick_np_queues; -+ unsigned int next_sched_frame; -+#ifdef FIQ_DEBUG -+ char * buffer; -+ unsigned int bufsiz; -+#endif -+ struct fiq_channel_state channel[0]; -+}; -+ -+extern int fiq_fsm_too_late(struct fiq_state *st, int n); -+ -+extern int fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n); -+ -+extern void dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels); -+ -+extern void dwc_otg_fiq_nop(struct fiq_state *state); -+ -+#endif /* DWC_OTG_FIQ_FSM_H_ */ -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S b/drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S -new file mode 100644 -index 0000000..8cfe364 ---- /dev/null -+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S -@@ -0,0 +1,81 @@ -+/* -+ * dwc_otg_fiq_fsm.S - assembly stub for the FSM FIQ -+ * -+ * Copyright (c) 2013 Raspberry Pi Foundation -+ * -+ * Author: Jonathan Bell -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * * Neither the name of Raspberry Pi nor the -+ * names of its contributors may be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+ -+#include -+#include -+ -+ -+.text -+ -+.global _dwc_otg_fiq_stub_end; -+ -+/** -+ * _dwc_otg_fiq_stub() - entry copied to the FIQ vector page to allow -+ * a C-style function call with arguments from the FIQ banked registers. -+ * r0 = &hcd->fiq_state -+ * r1 = &hcd->num_channels -+ * r2 = &hcd->dma_buffers -+ * Tramples: r0, r1, r2, r4, fp, ip -+ */ -+ -+ENTRY(_dwc_otg_fiq_stub) -+ /* Stash unbanked regs - SP will have been set up for us */ -+ mov ip, sp; -+ stmdb sp!, {r0-r12, lr}; -+#ifdef FIQ_DEBUG -+ // Cycle profiling - read cycle counter at start -+ mrc p15, 0, r5, c15, c12, 1; -+#endif -+ /* r11 = fp, don't trample it */ -+ mov r4, fp; -+ /* set EABI frame size */ -+ sub fp, ip, #512; -+ -+ /* for fiq NOP mode - just need state */ -+ mov r0, r8; -+ /* r9 = num_channels */ -+ mov r1, r9; -+ /* r10 = struct *dma_bufs */ -+// mov r2, r10; -+ -+ /* r4 = &fiq_c_function */ -+ blx r4; -+#ifdef FIQ_DEBUG -+ mrc p15, 0, r4, c15, c12, 1; -+ subs r5, r5, r4; -+ // r5 is now the cycle count time for executing the FIQ. Store it somewhere? -+#endif -+ ldmia sp!, {r0-r12, lr}; -+ subs pc, lr, #4; -+_dwc_otg_fiq_stub_end: -+END(_dwc_otg_fiq_stub) -+ -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 22300f0..e6b4a1e 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -45,9 +45,10 @@ - - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" --#include "dwc_otg_mphi_fix.h" -+#include "dwc_otg_fiq_fsm.h" - --extern bool microframe_schedule, nak_holdoff_enable; -+extern bool microframe_schedule; -+extern uint16_t fiq_fsm_mask, nak_holdoff; - - //#define DEBUG_HOST_CHANNELS - #ifdef DEBUG_HOST_CHANNELS -@@ -57,12 +58,6 @@ static int last_sel_trans_num_avail_hc_at_start = 0; - static int last_sel_trans_num_avail_hc_at_end = 0; - #endif /* DEBUG_HOST_CHANNELS */ - --extern int g_next_sched_frame, g_np_count, g_np_sent; -- --extern haint_data_t haint_saved; --extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; --extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; --extern gintsts_data_t ginsts_saved; - - dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) - { -@@ -295,7 +290,7 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) - */ - dwc_otg_hcd->flags.b.port_connect_status_change = 1; - dwc_otg_hcd->flags.b.port_connect_status = 0; -- if(fiq_fix_enable) -+ if(fiq_enable) - local_fiq_disable(); - /* - * Shutdown any transfers in process by clearing the Tx FIFO Empty -@@ -392,20 +387,15 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *p) - channel->qh = NULL; - } - } -- if(fiq_split_enable) { -+ if(fiq_fsm_enable) { - for(i=0; i < 128; i++) { - dwc_otg_hcd->hub_port[i] = 0; - } -- haint_saved.d32 = 0; -- for(i=0; i < MAX_EPS_CHANNELS; i++) { -- hcint_saved[i].d32 = 0; -- hcintmsk_saved[i].d32 = 0; -- } - } - - } - -- if(fiq_fix_enable) -+ if(fiq_enable) - local_fiq_enable(); - - if (dwc_otg_hcd->fops->disconnect) { -@@ -542,7 +532,7 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, - } - #endif - intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); -- if(!intr_mask.b.sofintr) needs_scheduling = 1; -+ if(!intr_mask.b.sofintr || fiq_enable) needs_scheduling = 1; - if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) - /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */ - needs_scheduling = 0; -@@ -613,6 +603,7 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, - if (urb_qtd->in_process && qh->channel) { - /* The QTD is in process (it has been assigned to a channel). */ - if (hcd->flags.b.port_connect_status) { -+ int n = qh->channel->hc_num; - /* - * If still connected (i.e. in host mode), halt the - * channel so it can be used for other transfers. If -@@ -620,10 +611,14 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, - * written to halt the channel since the core is in - * device mode. - */ -+ /* In FIQ FSM mode, we need to shut down carefully. -+ * The FIQ may attempt to restart a disabled channel */ -+ if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) { -+ hcd->fiq_state->channel[n].fsm = FIQ_DEQUEUE_ISSUED; -+ } - dwc_otg_hc_halt(hcd->core_if, qh->channel, - DWC_OTG_HC_XFER_URB_DEQUEUE); - -- dwc_otg_hcd_release_port(hcd, qh); - } - } - -@@ -759,7 +754,6 @@ static void completion_tasklet_func(void *ptr) - - usb_hcd_giveback_urb(hcd->priv, urb, urb->status); - -- fiq_print(FIQDBG_PORTHUB, "COMPLETE"); - - DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); - } -@@ -854,6 +848,34 @@ void dwc_otg_hcd_power_up(void *ptr) - cil_hcd_start(core_if); - } - -+void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num) -+{ -+ struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; -+ struct fiq_dma_blob *blob = hcd->fiq_dmab; -+ int i; -+ -+ st->fsm = FIQ_PASSTHROUGH; -+ st->hcchar_copy.d32 = 0; -+ st->hcsplt_copy.d32 = 0; -+ st->hcint_copy.d32 = 0; -+ st->hcintmsk_copy.d32 = 0; -+ st->hctsiz_copy.d32 = 0; -+ st->hcdma_copy.d32 = 0; -+ st->nr_errors = 0; -+ st->hub_addr = 0; -+ st->port_addr = 0; -+ st->expected_uframe = 0; -+ st->nrpackets = 0; -+ st->dma_info.index = 0; -+ for (i = 0; i < 6; i++) -+ st->dma_info.slot_len[i] = 255; -+ st->hs_isoc_info.index = 0; -+ st->hs_isoc_info.iso_desc = NULL; -+ st->hs_isoc_info.nrframes = 0; -+ -+ DWC_MEMSET(&blob->channel[num].index[0], 0x6b, 1128); -+} -+ - /** - * Frees secondary storage associated with the dwc_otg_hcd structure contained - * in the struct usb_hcd field. -@@ -907,6 +929,7 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) - DWC_TIMER_FREE(dwc_otg_hcd->conn_timer); - DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet); - DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet); -+ DWC_FREE(dwc_otg_hcd->fiq_state); - - #ifdef DWC_DEV_SRPCAP - if (dwc_otg_hcd->core_if->power_down == 2 && -@@ -979,6 +1002,59 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) - channel); - } - -+ if (fiq_enable) { -+ hcd->fiq_state = DWC_ALLOC(sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels)); -+ if (!hcd->fiq_state) { -+ retval = -DWC_E_NO_MEMORY; -+ DWC_ERROR("%s: cannot allocate fiq_state structure\n", __func__); -+ dwc_otg_hcd_free(hcd); -+ goto out; -+ } -+ DWC_MEMSET(hcd->fiq_state, 0, (sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels))); -+ -+ for (i = 0; i < num_channels; i++) { -+ hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH; -+ } -+ hcd->fiq_state->dummy_send = DWC_ALLOC_ATOMIC(16); -+ -+ hcd->fiq_stack = DWC_ALLOC(sizeof(struct fiq_stack)); -+ if (!hcd->fiq_stack) { -+ retval = -DWC_E_NO_MEMORY; -+ DWC_ERROR("%s: cannot allocate fiq_stack structure\n", __func__); -+ dwc_otg_hcd_free(hcd); -+ goto out; -+ } -+ hcd->fiq_stack->magic1 = 0xDEADBEEF; -+ hcd->fiq_stack->magic2 = 0xD00DFEED; -+ hcd->fiq_state->gintmsk_saved.d32 = ~0; -+ hcd->fiq_state->haintmsk_saved.b2.chint = ~0; -+ -+ /* This bit is terrible and uses no API, but necessary. The FIQ has no concept of DMA pools -+ * (and if it did, would be a lot slower). This allocates a chunk of memory (~9kiB for 8 host channels) -+ * for use as transaction bounce buffers in a 2-D array. Our access into this chunk is done by some -+ * moderately readable array casts. -+ */ -+ hcd->fiq_dmab = DWC_DMA_ALLOC((sizeof(struct fiq_dma_channel) * num_channels), &hcd->fiq_state->dma_base); -+ DWC_WARN("FIQ DMA bounce buffers: virt = 0x%08x dma = 0x%08x len=%d", -+ (unsigned int)hcd->fiq_dmab, (unsigned int)hcd->fiq_state->dma_base, -+ sizeof(struct fiq_dma_channel) * num_channels); -+ -+ DWC_MEMSET(hcd->fiq_dmab, 0x6b, 9024); -+ -+ /* pointer for debug in fiq_print */ -+ hcd->fiq_state->fiq_dmab = hcd->fiq_dmab; -+ if (fiq_fsm_enable) { -+ int i; -+ for (i=0; i < hcd->core_if->core_params->host_channels; i++) { -+ dwc_otg_cleanup_fiq_channel(hcd, i); -+ } -+ DWC_PRINTF("FIQ FSM acceleration enabled for :\n%s%s%s", -+ (fiq_fsm_mask & 0x1) ? "Non-periodic Split Transactions\n" : "", -+ (fiq_fsm_mask & 0x2) ? "Periodic Split Transactions\n" : "", -+ (fiq_fsm_mask & 0x4) ? "High-Speed Isochronous Endpoints\n" : ""); -+ } -+ } -+ - /* Initialize the Connection timeout timer. */ - hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer", - dwc_otg_hcd_connect_timeout, 0); -@@ -1176,7 +1252,8 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - hc->do_split = 1; - hc->xact_pos = qtd->isoc_split_pos; - /* We don't need to do complete splits anymore */ -- if(fiq_split_enable) -+// if(fiq_fsm_enable) -+ if (0) - hc->complete_split = qtd->complete_split = 0; - else - hc->complete_split = qtd->complete_split; -@@ -1327,62 +1404,487 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - hc->qh = qh; - } - --/* --** Check the transaction to see if the port / hub has already been assigned for --** a split transaction --** --** Return 0 - Port is already in use --*/ --int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) -+ -+/** -+ * fiq_fsm_transaction_suitable() - Test a QH for compatibility with the FIQ -+ * @qh: pointer to the endpoint's queue head -+ * -+ * Transaction start/end control flow is grafted onto the existing dwc_otg -+ * mechanisms, to avoid spaghettifying the functions more than they already are. -+ * This function's eligibility check is altered by debug parameter. -+ * -+ * Returns: 0 for unsuitable, 1 implies the FIQ can be enabled for this transaction. -+ */ -+ -+int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh) - { -- uint32_t hub_addr, port_addr; -+ if (qh->do_split) { -+ switch (qh->ep_type) { -+ case UE_CONTROL: -+ case UE_BULK: -+ if (fiq_fsm_mask & (1 << 0)) -+ return 1; -+ break; -+ case UE_INTERRUPT: -+ case UE_ISOCHRONOUS: -+ if (fiq_fsm_mask & (1 << 1)) -+ return 1; -+ break; -+ default: -+ break; -+ } -+ } else if (qh->ep_type == UE_ISOCHRONOUS) { -+ if (fiq_fsm_mask & (1 << 2)) { -+ /* HS ISOCH support. We test for compatibility: -+ * - DWORD aligned buffers -+ * - Must be at least 2 transfers (otherwise pointless to use the FIQ) -+ * If yes, then the fsm enqueue function will handle the state machine setup. -+ */ -+ dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); -+ dwc_otg_hcd_urb_t *urb = qtd->urb; -+ struct dwc_otg_hcd_iso_packet_desc (*iso_descs)[0] = &urb->iso_descs; -+ int nr_iso_frames = urb->packet_count; -+ int i; -+ uint32_t ptr; -+ -+ if (nr_iso_frames < 2) -+ return 0; -+ for (i = 0; i < nr_iso_frames; i++) { -+ ptr = urb->dma + iso_descs[i]->offset; -+ if (ptr & 0x3) { -+ printk_ratelimited("%s: Non-Dword aligned isochronous frame offset." -+ " Cannot queue FIQ-accelerated transfer to device %d endpoint %d\n", -+ __FUNCTION__, qh->channel->dev_addr, qh->channel->ep_num); -+ return 0; -+ } -+ } -+ return 1; -+ } -+ } -+ return 0; -+} - -- if(!fiq_split_enable) -- return 0; -+/** -+ * fiq_fsm_setup_periodic_dma() - Set up DMA bounce buffers -+ * @hcd: Pointer to the dwc_otg_hcd struct -+ * @qh: Pointer to the endpoint's queue head -+ * -+ * Periodic split transactions are transmitted modulo 188 bytes. -+ * This necessitates slicing data up into buckets for isochronous out -+ * and fixing up the DMA address for all IN transfers. -+ * -+ * Returns 1 if the DMA bounce buffers have been used, 0 if the default -+ * HC buffer has been used. -+ */ -+int fiq_fsm_setup_periodic_dma(dwc_otg_hcd_t *hcd, struct fiq_channel_state *st, dwc_otg_qh_t *qh) -+ { -+ int frame_length, i = 0; -+ uint8_t *ptr = NULL; -+ dwc_hc_t *hc = qh->channel; -+ struct fiq_dma_blob *blob; -+ struct dwc_otg_hcd_iso_packet_desc *frame_desc; -+ -+ for (i = 0; i < 6; i++) { -+ st->dma_info.slot_len[i] = 255; -+ } -+ st->dma_info.index = 0; -+ i = 0; -+ if (hc->ep_is_in) { -+ /* -+ * Set dma_regs to bounce buffer. FIQ will update the -+ * state depending on transaction progress. -+ */ -+ blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base; -+ st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0]; -+ /* Calculate the max number of CSPLITS such that the FIQ can time out -+ * a transaction if it fails. -+ */ -+ frame_length = st->hcchar_copy.b.mps; -+ do { -+ i++; -+ frame_length -= 188; -+ } while (frame_length >= 0); -+ st->nrpackets = i; -+ return 1; -+ } else { -+ if (qh->ep_type == UE_ISOCHRONOUS) { - -- hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); -+ dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); - -- if(hcd->hub_port[hub_addr] & (1 << port_addr)) -- { -- fiq_print(FIQDBG_PORTHUB, "H%dP%d:S%02d", hub_addr, port_addr, qh->skip_count); -+ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; -+ frame_length = frame_desc->length; - -- qh->skip_count++; -+ /* Virtual address for bounce buffers */ -+ blob = hcd->fiq_dmab; - -- if(qh->skip_count > 40000) -- { -- printk_once(KERN_ERR "Error: Having to skip port allocation"); -- local_fiq_disable(); -- BUG(); -+ ptr = qtd->urb->buf + frame_desc->offset; -+ if (frame_length == 0) { -+ /* -+ * for isochronous transactions, we must still transmit a packet -+ * even if the length is zero. -+ */ -+ st->dma_info.slot_len[0] = 0; -+ st->nrpackets = 1; -+ } else { -+ do { -+ if (frame_length <= 188) { -+ dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, frame_length); -+ st->dma_info.slot_len[i] = frame_length; -+ ptr += frame_length; -+ } else { -+ dwc_memcpy(&blob->channel[hc->hc_num].index[i].buf[0], ptr, 188); -+ st->dma_info.slot_len[i] = 188; -+ ptr += 188; -+ } -+ i++; -+ frame_length -= 188; -+ } while (frame_length > 0); -+ st->nrpackets = i; -+ } -+ ptr = qtd->urb->buf + frame_desc->offset; -+ /* Point the HC at the DMA address of the bounce buffers */ -+ blob = (struct fiq_dma_blob *) hcd->fiq_state->dma_base; -+ st->hcdma_copy.d32 = (uint32_t) &blob->channel[hc->hc_num].index[0].buf[0]; -+ -+ /* fixup xfersize to the actual packet size */ -+ st->hctsiz_copy.b.pid = 0; -+ st->hctsiz_copy.b.xfersize = st->dma_info.slot_len[0]; -+ return 1; -+ } else { -+ /* For interrupt, single OUT packet required, goes in the SSPLIT from hc_buff. */ - return 0; - } -- return 1; - } -- else -- { -- qh->skip_count = 0; -- hcd->hub_port[hub_addr] |= 1 << port_addr; -- fiq_print(FIQDBG_PORTHUB, "H%dP%d:A %d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); --#ifdef FIQ_DEBUG -- hcd->hub_port_alloc[hub_addr * 16 + port_addr] = dwc_otg_hcd_get_frame_number(hcd); --#endif -+} -+ -+/* -+ * Pushing a periodic request into the queue near the EOF1 point -+ * in a microframe causes erroneous behaviour (frmovrun) interrupt. -+ * Usually, the request goes out on the bus causing a transfer but -+ * the core does not transfer the data to memory. -+ * This guard interval (in number of 60MHz clocks) is required which -+ * must cater for CPU latency between reading the value and enabling -+ * the channel. -+ */ -+#define PERIODIC_FRREM_BACKOFF 1000 -+ -+int fiq_fsm_queue_isoc_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) -+{ -+ dwc_hc_t *hc = qh->channel; -+ dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; -+ dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); -+ int frame; -+ struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num]; -+ int xfer_len, nrpackets; -+ hcdma_data_t hcdma; -+ hfnum_data_t hfnum; -+ -+ if (st->fsm != FIQ_PASSTHROUGH) - return 0; -+ -+ st->nr_errors = 0; -+ -+ st->hcchar_copy.d32 = 0; -+ st->hcchar_copy.b.mps = hc->max_packet; -+ st->hcchar_copy.b.epdir = hc->ep_is_in; -+ st->hcchar_copy.b.devaddr = hc->dev_addr; -+ st->hcchar_copy.b.epnum = hc->ep_num; -+ st->hcchar_copy.b.eptype = hc->ep_type; -+ -+ st->hcintmsk_copy.b.chhltd = 1; -+ -+ frame = dwc_otg_hcd_get_frame_number(hcd); -+ st->hcchar_copy.b.oddfrm = (frame & 0x1) ? 0 : 1; -+ -+ st->hcchar_copy.b.lspddev = 0; -+ /* Enable the channel later as a final register write. */ -+ -+ st->hcsplt_copy.d32 = 0; -+ -+ st->hs_isoc_info.iso_desc = (struct dwc_otg_hcd_iso_packet_desc *) &qtd->urb->iso_descs; -+ st->hs_isoc_info.nrframes = qtd->urb->packet_count; -+ /* grab the next DMA address offset from the array */ -+ st->hcdma_copy.d32 = qtd->urb->dma; -+ hcdma.d32 = st->hcdma_copy.d32 + st->hs_isoc_info.iso_desc[0].offset; -+ -+ /* We need to set multi_count. This is a bit tricky - has to be set per-transaction as -+ * the core needs to be told to send the correct number. Caution: for IN transfers, -+ * this is always set to the maximum size of the endpoint. */ -+ xfer_len = st->hs_isoc_info.iso_desc[0].length; -+ nrpackets = (xfer_len + st->hcchar_copy.b.mps - 1) / st->hcchar_copy.b.mps; -+ if (nrpackets == 0) -+ nrpackets = 1; -+ st->hcchar_copy.b.multicnt = nrpackets; -+ st->hctsiz_copy.b.pktcnt = nrpackets; -+ -+ /* Initial PID also needs to be set */ -+ if (st->hcchar_copy.b.epdir == 0) { -+ st->hctsiz_copy.b.xfersize = xfer_len; -+ switch (st->hcchar_copy.b.multicnt) { -+ case 1: -+ st->hctsiz_copy.b.pid = DWC_PID_DATA0; -+ break; -+ case 2: -+ case 3: -+ st->hctsiz_copy.b.pid = DWC_PID_MDATA; -+ break; -+ } -+ -+ } else { -+ st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps; -+ switch (st->hcchar_copy.b.multicnt) { -+ case 1: -+ st->hctsiz_copy.b.pid = DWC_PID_DATA0; -+ break; -+ case 2: -+ st->hctsiz_copy.b.pid = DWC_PID_DATA1; -+ break; -+ case 3: -+ st->hctsiz_copy.b.pid = DWC_PID_DATA2; -+ break; -+ } - } -+ -+ fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d ", hc->hc_num); -+ fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcchar_copy.d32); -+ fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32); -+ fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32); -+ hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); -+ local_fiq_disable(); -+ DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32); -+ DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32); -+ DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32); -+ DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); -+ DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32); -+ if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) { -+ /* Prevent queueing near EOF1. Bad things happen if a periodic -+ * split transaction is queued very close to EOF. -+ */ -+ st->fsm = FIQ_HS_ISOC_SLEEPING; -+ } else { -+ st->fsm = FIQ_HS_ISOC_TURBO; -+ st->hcchar_copy.b.chen = 1; -+ DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); -+ } -+ mb(); -+ st->hcchar_copy.b.chen = 0; -+ local_fiq_enable(); -+ return 0; - } --void dwc_otg_hcd_release_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) -+ -+ -+/** -+ * fiq_fsm_queue_split_transaction() - Set up a host channel and FIQ state -+ * @hcd: Pointer to the dwc_otg_hcd struct -+ * @qh: Pointer to the endpoint's queue head -+ * -+ * This overrides the dwc_otg driver's normal method of queueing a transaction. -+ * Called from dwc_otg_hcd_queue_transactions(), this performs specific setup -+ * for the nominated host channel. -+ * -+ * For periodic transfers, it also peeks at the FIQ state to see if an immediate -+ * start is possible. If not, then the FIQ is left to start the transfer. -+ */ -+int fiq_fsm_queue_split_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) - { -- uint32_t hub_addr, port_addr; -+ int start_immediate = 1, i; -+ hfnum_data_t hfnum; -+ dwc_hc_t *hc = qh->channel; -+ dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; -+ /* Program HC registers, setup FIQ_state, examine FIQ if periodic, start transfer (not if uframe 5) */ -+ int hub_addr, port_addr, frame, uframe; -+ struct fiq_channel_state *st = &hcd->fiq_state->channel[hc->hc_num]; - -- if(!fiq_split_enable) -- return; -+ if (st->fsm != FIQ_PASSTHROUGH) -+ return 0; -+ st->nr_errors = 0; -+ -+ st->hcchar_copy.d32 = 0; -+ st->hcchar_copy.b.mps = hc->max_packet; -+ st->hcchar_copy.b.epdir = hc->ep_is_in; -+ st->hcchar_copy.b.devaddr = hc->dev_addr; -+ st->hcchar_copy.b.epnum = hc->ep_num; -+ st->hcchar_copy.b.eptype = hc->ep_type; -+ if (hc->ep_type & 0x1) { -+ if (hc->ep_is_in) -+ st->hcchar_copy.b.multicnt = 3; -+ else -+ /* Docs say set this to 1, but driver sets to 0! */ -+ st->hcchar_copy.b.multicnt = 0; -+ } else { -+ st->hcchar_copy.b.multicnt = 1; -+ st->hcchar_copy.b.oddfrm = 0; -+ } -+ st->hcchar_copy.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW) ? 1 : 0; -+ /* Enable the channel later as a final register write. */ -+ -+ st->hcsplt_copy.d32 = 0; -+ if(qh->do_split) { -+ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); -+ st->hcsplt_copy.b.compsplt = 0; -+ st->hcsplt_copy.b.spltena = 1; -+ // XACTPOS is for isoc-out only but needs initialising anyway. -+ st->hcsplt_copy.b.xactpos = ISOC_XACTPOS_ALL; -+ if((qh->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!qh->ep_is_in)) { -+ /* For packetsize 0 < L < 188, ISOC_XACTPOS_ALL. -+ * for longer than this, ISOC_XACTPOS_BEGIN and the FIQ -+ * will update as necessary. -+ */ -+ if (hc->xfer_len > 188) { -+ st->hcsplt_copy.b.xactpos = ISOC_XACTPOS_BEGIN; -+ } -+ } -+ st->hcsplt_copy.b.hubaddr = (uint8_t) hub_addr; -+ st->hcsplt_copy.b.prtaddr = (uint8_t) port_addr; -+ st->hub_addr = hub_addr; -+ st->port_addr = port_addr; -+ } - -- hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); -+ st->hctsiz_copy.d32 = 0; -+ st->hctsiz_copy.b.dopng = 0; -+ st->hctsiz_copy.b.pid = hc->data_pid_start; - -- hcd->hub_port[hub_addr] &= ~(1 << port_addr); --#ifdef FIQ_DEBUG -- hcd->hub_port_alloc[hub_addr * 16 + port_addr] = -1; --#endif -- fiq_print(FIQDBG_PORTHUB, "H%dP%d:RO%d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); -+ if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) { -+ hc->xfer_len = hc->max_packet; -+ } else if (!hc->ep_is_in && (hc->xfer_len > 188)) { -+ hc->xfer_len = 188; -+ } -+ st->hctsiz_copy.b.xfersize = hc->xfer_len; - -+ st->hctsiz_copy.b.pktcnt = 1; -+ -+ if (hc->ep_type & 0x1) { -+ /* -+ * For potentially multi-packet transfers, must use the DMA bounce buffers. For IN transfers, -+ * the DMA address is the address of the first 188byte slot buffer in the bounce buffer array. -+ * For multi-packet OUT transfers, we need to copy the data into the bounce buffer array so the FIQ can punt -+ * the right address out as necessary. hc->xfer_buff and hc->xfer_len have already been set -+ * in assign_and_init_hc(), but this is for the eventual transaction completion only. The FIQ -+ * must not touch internal driver state. -+ */ -+ if(!fiq_fsm_setup_periodic_dma(hcd, st, qh)) { -+ if (hc->align_buff) { -+ st->hcdma_copy.d32 = hc->align_buff; -+ } else { -+ st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); -+ } -+ } -+ } else { -+ if (hc->align_buff) { -+ st->hcdma_copy.d32 = hc->align_buff; -+ } else { -+ st->hcdma_copy.d32 = ((unsigned long) hc->xfer_buff & 0xFFFFFFFF); -+ } -+ } -+ /* The FIQ depends upon no other interrupts being enabled except channel halt. -+ * Fixup channel interrupt mask. */ -+ st->hcintmsk_copy.d32 = 0; -+ st->hcintmsk_copy.b.chhltd = 1; -+ st->hcintmsk_copy.b.ahberr = 1; -+ -+ DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32); -+ DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32); -+ DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32); -+ DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); -+ DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32); -+ -+ local_fiq_disable(); -+ mb(); -+ -+ if (hc->ep_type & 0x1) { -+ hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); -+ frame = (hfnum.b.frnum & ~0x7) >> 3; -+ uframe = hfnum.b.frnum & 0x7; -+ if (hfnum.b.frrem < PERIODIC_FRREM_BACKOFF) { -+ /* Prevent queueing near EOF1. Bad things happen if a periodic -+ * split transaction is queued very close to EOF. -+ */ -+ start_immediate = 0; -+ } else if (uframe == 5) { -+ start_immediate = 0; -+ } else if (hc->ep_type == UE_ISOCHRONOUS && !hc->ep_is_in) { -+ start_immediate = 0; -+ } else if (hc->ep_is_in && fiq_fsm_too_late(hcd->fiq_state, hc->hc_num)) { -+ start_immediate = 0; -+ } else { -+ /* Search through all host channels to determine if a transaction -+ * is currently in progress */ -+ for (i = 0; i < hcd->core_if->core_params->host_channels; i++) { -+ if (i == hc->hc_num || hcd->fiq_state->channel[i].fsm == FIQ_PASSTHROUGH) -+ continue; -+ switch (hcd->fiq_state->channel[i].fsm) { -+ /* TT is reserved for channels that are in the middle of a periodic -+ * split transaction. -+ */ -+ case FIQ_PER_SSPLIT_STARTED: -+ case FIQ_PER_CSPLIT_WAIT: -+ case FIQ_PER_CSPLIT_NYET1: -+ case FIQ_PER_CSPLIT_POLL: -+ case FIQ_PER_ISO_OUT_ACTIVE: -+ case FIQ_PER_ISO_OUT_LAST: -+ if (hcd->fiq_state->channel[i].hub_addr == hub_addr && -+ hcd->fiq_state->channel[i].port_addr == port_addr) { -+ start_immediate = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ if (!start_immediate) -+ break; -+ } -+ } -+ } -+ fiq_print(FIQDBG_INT, hcd->fiq_state, "FSMQ %01d %01d", hc->hc_num, start_immediate); -+ fiq_print(FIQDBG_INT, hcd->fiq_state, "%08d", hfnum.b.frrem); -+ //fiq_print(FIQDBG_INT, hcd->fiq_state, "H:%02dP:%02d", hub_addr, port_addr); -+ //fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hctsiz_copy.d32); -+ //fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32); -+ switch (hc->ep_type) { -+ case UE_CONTROL: -+ case UE_BULK: -+ st->fsm = FIQ_NP_SSPLIT_STARTED; -+ break; -+ case UE_ISOCHRONOUS: -+ if (hc->ep_is_in) { -+ if (start_immediate) { -+ st->fsm = FIQ_PER_SSPLIT_STARTED; -+ } else { -+ st->fsm = FIQ_PER_SSPLIT_QUEUED; -+ } -+ } else { -+ if (start_immediate) { -+ /* Single-isoc OUT packets don't require FIQ involvement */ -+ if (st->nrpackets == 1) { -+ st->fsm = FIQ_PER_ISO_OUT_LAST; -+ } else { -+ st->fsm = FIQ_PER_ISO_OUT_ACTIVE; -+ } -+ } else { -+ st->fsm = FIQ_PER_ISO_OUT_PENDING; -+ } -+ } -+ break; -+ case UE_INTERRUPT: -+ if (start_immediate) { -+ st->fsm = FIQ_PER_SSPLIT_STARTED; -+ } else { -+ st->fsm = FIQ_PER_SSPLIT_QUEUED; -+ } -+ default: -+ break; -+ } -+ if (start_immediate) { -+ /* Set the oddfrm bit as close as possible to actual queueing */ -+ frame = dwc_otg_hcd_get_frame_number(hcd); -+ st->expected_uframe = (frame + 1) & 0x3FFF; -+ st->hcchar_copy.b.oddfrm = (frame & 0x1) ? 0 : 1; -+ st->hcchar_copy.b.chen = 1; -+ DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32); -+ } -+ mb(); -+ local_fiq_enable(); -+ return 0; - } - - -@@ -1399,16 +1901,11 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - { - dwc_list_link_t *qh_ptr; - dwc_otg_qh_t *qh; -- dwc_otg_qtd_t *qtd; - int num_channels; - dwc_irqflags_t flags; - dwc_spinlock_t *channel_lock = hcd->channel_lock; - dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; - --#ifdef DEBUG_SOF -- DWC_DEBUGPL(DBG_HCD, " Select Transactions\n"); --#endif -- - #ifdef DEBUG_HOST_CHANNELS - last_sel_trans_num_per_scheduled = 0; - last_sel_trans_num_nonper_scheduled = 0; -@@ -1423,26 +1920,11 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - - qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); - -- if(qh->do_split) { -- qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); -- if(!(qh->ep_type == UE_ISOCHRONOUS && -- (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID || -- qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))) { -- if(dwc_otg_hcd_allocate_port(hcd, qh)) -- { -- qh_ptr = DWC_LIST_NEXT(qh_ptr); -- g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); -- continue; -- } -- } -- } -- - if (microframe_schedule) { - // Make sure we leave one channel for non periodic transactions. - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - if (hcd->available_host_channels <= 1) { - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); -- if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh); - break; - } - hcd->available_host_channels--; -@@ -1478,27 +1960,24 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { - - qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); -- - /* - * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission - * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed - * cheeky devices that just hold off using NAKs - */ -- if (nak_holdoff_enable && qh->do_split) { -- if (qh->nak_frame != 0xffff && -- dwc_full_frame_num(qh->nak_frame) == -- dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { -- /* -- * Revisit: Need to avoid trampling on periodic scheduling. -- * Currently we are safe because g_np_count != g_np_sent whenever we hit this, -- * but if this behaviour is changed then periodic endpoints will get a slower -- * polling rate. -- */ -- g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; -- qh_ptr = DWC_LIST_NEXT(qh_ptr); -- continue; -- } else { -- qh->nak_frame = 0xffff; -+ if (nak_holdoff && qh->do_split) { -+ if (qh->nak_frame != 0xffff) { -+ uint16_t next_frame = dwc_frame_num_inc(qh->nak_frame, (qh->ep_type == UE_BULK) ? nak_holdoff : 8); -+ uint16_t frame = dwc_otg_hcd_get_frame_number(hcd); -+ if (dwc_frame_num_le(frame, next_frame)) { -+ if(dwc_frame_num_le(next_frame, hcd->fiq_state->next_sched_frame)) { -+ hcd->fiq_state->next_sched_frame = next_frame; -+ } -+ qh_ptr = DWC_LIST_NEXT(qh_ptr); -+ continue; -+ } else { -+ qh->nak_frame = 0xFFFF; -+ } - } - } - -@@ -1527,12 +2006,29 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - &qh->qh_list_entry); - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - -- g_np_sent++; - - if (!microframe_schedule) - hcd->non_periodic_channels++; - } -- -+ /* we moved a non-periodic QH to the active schedule. If the inactive queue is empty, -+ * stop the FIQ from kicking us. We could potentially still have elements here if we -+ * ran out of host channels. -+ */ -+ if (DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive)) { -+ hcd->fiq_state->kick_np_queues = 0; -+ } else { -+ /* For each entry remaining in the NP inactive queue, -+ * if this a NAK'd retransmit then don't set the kick flag. -+ */ -+ if(nak_holdoff) { -+ DWC_LIST_FOREACH(qh_ptr, &hcd->non_periodic_sched_inactive) { -+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ if (qh->nak_frame == 0xFFFF) { -+ hcd->fiq_state->kick_np_queues = 1; -+ } -+ } -+ } -+ } - if(!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) - ret_val |= DWC_OTG_TRANSACTION_PERIODIC; - -@@ -1577,6 +2073,12 @@ static int queue_transaction(dwc_otg_hcd_t * hcd, - hc->qh->ping_state = 0; - } - } else if (!hc->xfer_started) { -+ if (fiq_fsm_enable && hc->error_state) { -+ hcd->fiq_state->channel[hc->hc_num].nr_errors = -+ DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list)->error_count; -+ hcd->fiq_state->channel[hc->hc_num].fsm = -+ FIQ_PASSTHROUGH_ERRORSTATE; -+ } - dwc_otg_hc_start_transfer(hcd->core_if, hc); - hc->qh->ping_state = 0; - } -@@ -1629,7 +2131,7 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) - hptxsts_data_t tx_status; - dwc_list_link_t *qh_ptr; - dwc_otg_qh_t *qh; -- int status; -+ int status = 0; - int no_queue_space = 0; - int no_fifo_space = 0; - -@@ -1658,27 +2160,34 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd) - - // Do not send a split start transaction any later than frame .6 - // Note, we have to schedule a periodic in .5 to make it go in .6 -- if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) -+ if(fiq_fsm_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) - { - qh_ptr = qh_ptr->next; -- g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; -+ hcd->fiq_state->next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; - continue; - } - -- /* -- * Set a flag if we're queuing high-bandwidth in slave mode. -- * The flag prevents any halts to get into the request queue in -- * the middle of multiple high-bandwidth packets getting queued. -- */ -- if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) { -- hcd->core_if->queuing_high_bandwidth = 1; -- } -- status = -- queue_transaction(hcd, qh->channel, -- tx_status.b.ptxfspcavail); -- if (status < 0) { -- no_fifo_space = 1; -- break; -+ if (fiq_fsm_enable && fiq_fsm_transaction_suitable(qh)) { -+ if (qh->do_split) -+ fiq_fsm_queue_split_transaction(hcd, qh); -+ else -+ fiq_fsm_queue_isoc_transaction(hcd, qh); -+ } else { -+ -+ /* -+ * Set a flag if we're queueing high-bandwidth in slave mode. -+ * The flag prevents any halts to get into the request queue in -+ * the middle of multiple high-bandwidth packets getting queued. -+ */ -+ if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) { -+ hcd->core_if->queuing_high_bandwidth = 1; -+ } -+ status = queue_transaction(hcd, qh->channel, -+ tx_status.b.ptxfspcavail); -+ if (status < 0) { -+ no_fifo_space = 1; -+ break; -+ } - } - - /* -@@ -1795,25 +2304,19 @@ static void process_non_periodic_channels(dwc_otg_hcd_t * hcd) - qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t, - qh_list_entry); - -- // Do not send a split start transaction any later than frame .5 -- // non periodic transactions will start immediately in this uframe -- if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) -- { -- g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; -- break; -- } -- -- status = -- queue_transaction(hcd, qh->channel, -- tx_status.b.nptxfspcavail); -+ if(fiq_fsm_enable && fiq_fsm_transaction_suitable(qh)) { -+ fiq_fsm_queue_split_transaction(hcd, qh); -+ } else { -+ status = queue_transaction(hcd, qh->channel, -+ tx_status.b.nptxfspcavail); - -- if (status > 0) { -- more_to_do = 1; -- } else if (status < 0) { -- no_fifo_space = 1; -- break; -+ if (status > 0) { -+ more_to_do = 1; -+ } else if (status < 0) { -+ no_fifo_space = 1; -+ break; -+ } - } -- - /* Advance to next QH, skipping start-of-list entry. */ - hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next; - if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) { -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -index 0007fa1..da2986244 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h -@@ -40,6 +40,8 @@ - #include "dwc_otg_core_if.h" - #include "dwc_list.h" - #include "dwc_otg_cil.h" -+#include "dwc_otg_fiq_fsm.h" -+ - - /** - * @file -@@ -585,6 +587,12 @@ struct dwc_otg_hcd { - /** Frame List DMA address */ - dma_addr_t frame_list_dma; - -+ struct fiq_stack *fiq_stack; -+ struct fiq_state *fiq_state; -+ -+ /** Virtual address for split transaction DMA bounce buffers */ -+ struct fiq_dma_blob *fiq_dmab; -+ - #ifdef DEBUG - uint32_t frrem_samples; - uint64_t frrem_accum; -@@ -615,6 +623,9 @@ extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, - int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh); - void dwc_otg_hcd_release_port(dwc_otg_hcd_t * dwc_otg_hcd, dwc_otg_qh_t *qh); - -+extern int fiq_fsm_queue_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh); -+extern int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh); -+extern void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num); - - /** @} */ - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index 64d33a5..be8ef1b 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -34,7 +34,6 @@ - - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" --#include "dwc_otg_mphi_fix.h" - - #include - #include -@@ -47,33 +46,8 @@ extern bool microframe_schedule; - * This file contains the implementation of the HCD Interrupt handlers. - */ - --/* -- * Some globals to communicate between the FIQ and INTERRUPT -- */ -- --void * dummy_send; --mphi_regs_t c_mphi_regs; --volatile void *dwc_regs_base; - int fiq_done, int_done; - --gintsts_data_t gintsts_saved = {.d32 = 0}; --hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; --hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; --int split_out_xfersize[MAX_EPS_CHANNELS]; --haint_data_t haint_saved; -- --int g_next_sched_frame, g_np_count, g_np_sent; --static int mphi_int_count = 0 ; -- --hcchar_data_t nak_hcchar; --hctsiz_data_t nak_hctsiz; --hcsplt_data_t nak_hcsplt; --int nak_count; -- --int complete_sched[MAX_EPS_CHANNELS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; --int split_start_frame[MAX_EPS_CHANNELS]; --int queued_port[MAX_EPS_CHANNELS]; -- - #ifdef FIQ_DEBUG - char buffer[1000*16]; - int wptr; -@@ -83,12 +57,10 @@ void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) - va_list args; - char text[17]; - hfnum_data_t hfnum = { .d32 = FIQ_READ(dwc_regs_base + 0x408) }; -- unsigned long flags; - -- local_irq_save(flags); -- local_fiq_disable(); - if(dbg_lvl & dbg_lvl_req || dbg_lvl == FIQDBG_ERR) - { -+ local_fiq_disable(); - snprintf(text, 9, "%4d%d:%d ", hfnum.b.frnum/8, hfnum.b.frnum%8, 8 - hfnum.b.frrem/937); - va_start(args, fmt); - vsnprintf(text+8, 9, fmt, args); -@@ -96,410 +68,21 @@ void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) - - memcpy(buffer + wptr, text, 16); - wptr = (wptr + 16) % sizeof(buffer); -+ local_fiq_enable(); - } -- local_irq_restore(flags); - } - #endif - --void notrace fiq_queue_request(int channel, int odd_frame) --{ -- hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; -- hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; -- hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10) }; -- -- if(hcsplt.b.spltena == 0) -- { -- fiq_print(FIQDBG_ERR, "SPLTENA "); -- BUG(); -- } -- -- if(hcchar.b.epdir == 1) -- { -- fiq_print(FIQDBG_SCHED, "IN Ch %d", channel); -- } -- else -- { -- hctsiz.b.xfersize = 0; -- fiq_print(FIQDBG_SCHED, "OUT Ch %d", channel); -- } -- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x10), hctsiz.d32); -- -- hcsplt.b.compsplt = 1; -- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x4), hcsplt.d32); -- -- // Send the Split complete -- hcchar.b.chen = 1; -- hcchar.b.oddfrm = odd_frame ? 1 : 0; -- -- // Post this for transmit on the next frame for periodic or this frame for non-periodic -- fiq_print(FIQDBG_SCHED, "SND_%s", odd_frame ? "ODD " : "EVEN"); -- -- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x0), hcchar.d32); --} -- --static int last_sof = -1; -- --/* --** Function to handle the start of frame interrupt, choose whether we need to do anything and --** therefore trigger the main interrupt --** --** returns int != 0 - interrupt has been handled --*/ --int diff; -- --int notrace fiq_sof_handle(hfnum_data_t hfnum) --{ -- int handled = 0; -- int i; -- -- // Just check that once we're running we don't miss a SOF -- /*if(last_sof != -1 && (hfnum.b.frnum != ((last_sof + 1) & 0x3fff))) -- { -- fiq_print(FIQDBG_ERR, "LASTSOF "); -- fiq_print(FIQDBG_ERR, "%4d%d ", last_sof / 8, last_sof & 7); -- fiq_print(FIQDBG_ERR, "%4d%d ", hfnum.b.frnum / 8, hfnum.b.frnum & 7); -- BUG(); -- }*/ -- -- // Only start remembering the last sof when the interrupt has been -- // enabled (we don't check the mask to come in here...) -- if(last_sof != -1 || FIQ_READ(dwc_regs_base + 0x18) & (1<<3)) -- last_sof = hfnum.b.frnum; -- -- for(i = 0; i < MAX_EPS_CHANNELS; i++) -- { -- if(complete_sched[i] != -1) -- { -- if(complete_sched[i] <= hfnum.b.frnum || (complete_sched[i] > 0x3f00 && hfnum.b.frnum < 0xf0)) -- { -- fiq_queue_request(i, hfnum.b.frnum & 1); -- complete_sched[i] = -1; -- } -- } -- -- if(complete_sched[i] != -1) -- { -- // This is because we've seen a split complete occur with no start... -- // most likely because missed the complete 0x3fff frames ago! -- -- diff = (hfnum.b.frnum + 0x3fff - complete_sched[i]) & 0x3fff ; -- if(diff > 32 && diff < 0x3f00) -- { -- fiq_print(FIQDBG_ERR, "SPLTMISS"); -- BUG(); -- } -- } -- } -- -- if(g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) -- { -- /* -- * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet -- * g_next_sched_frame is the next frame we have periodic packets for -- * -- * if neither of these are required for this frame then just clear the interrupt -- */ -- handled = 1; -- -- } -- -- return handled; --} -- --int notrace port_id(hcsplt_data_t hcsplt) --{ -- return hcsplt.b.prtaddr + (hcsplt.b.hubaddr << 8); --} -- --int notrace fiq_hcintr_handle(int channel, hfnum_data_t hfnum) --{ -- hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; -- hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; -- hcint_data_t hcint = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x8) }; -- hcintmsk_data_t hcintmsk = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0xc) }; -- hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10)}; -- -- hcint_saved[channel].d32 |= hcint.d32; -- hcintmsk_saved[channel].d32 = hcintmsk.d32; -- -- if(hcsplt.b.spltena) -- { -- fiq_print(FIQDBG_PORTHUB, "ph: %4x", port_id(hcsplt)); -- if(hcint.b.chhltd) -- { -- fiq_print(FIQDBG_SCHED, "CH HLT %d", channel); -- fiq_print(FIQDBG_SCHED, "%08x", hcint_saved[channel]); -- } -- if(hcint.b.stall || hcint.b.xacterr || hcint.b.bblerr || hcint.b.frmovrun || hcint.b.datatglerr) -- { -- queued_port[channel] = 0; -- fiq_print(FIQDBG_ERR, "CHAN ERR"); -- } -- if(hcint.b.xfercomp) -- { -- // Clear the port allocation and transmit anything also on this port -- queued_port[channel] = 0; -- fiq_print(FIQDBG_SCHED, "XFERCOMP"); -- } -- if(hcint.b.nak) -- { -- queued_port[channel] = 0; -- fiq_print(FIQDBG_SCHED, "NAK"); -- } -- if(hcint.b.ack && !hcsplt.b.compsplt) -- { -- int i; -- -- // Do not complete isochronous out transactions -- if(hcchar.b.eptype == 1 && hcchar.b.epdir == 0) -- { -- queued_port[channel] = 0; -- fiq_print(FIQDBG_SCHED, "ISOC_OUT"); -- } -- else -- { -- // Make sure we check the port / hub combination that we sent this split on. -- // Do not queue a second request to the same port -- for(i = 0; i < MAX_EPS_CHANNELS; i++) -- { -- if(port_id(hcsplt) == queued_port[i]) -- { -- fiq_print(FIQDBG_ERR, "PORTERR "); -- //BUG(); -- } -- } -- -- split_start_frame[channel] = (hfnum.b.frnum + 1) & ~7; -- -- // Note, the size of an OUT is in the start split phase, not -- // the complete split -- split_out_xfersize[channel] = hctsiz.b.xfersize; -- -- hcint_saved[channel].b.chhltd = 0; -- hcint_saved[channel].b.ack = 0; -- -- queued_port[channel] = port_id(hcsplt); -- -- if(hcchar.b.eptype & 1) -- { -- // Send the periodic complete in the same oddness frame as the ACK went... -- fiq_queue_request(channel, !(hfnum.b.frnum & 1)); -- // complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1); -- } -- else -- { -- // Schedule the split complete to occur later -- complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 2); -- fiq_print(FIQDBG_SCHED, "ACK%04d%d", complete_sched[channel]/8, complete_sched[channel]%8); -- } -- } -- } -- if(hcint.b.nyet) -- { -- fiq_print(FIQDBG_ERR, "NYETERR1"); -- //BUG(); -- // Can transmit a split complete up to uframe .0 of the next frame -- if(hfnum.b.frnum <= dwc_frame_num_inc(split_start_frame[channel], 8)) -- { -- // Send it next frame -- if(hcchar.b.eptype & 1) // type 1 & 3 are interrupt & isoc -- { -- fiq_print(FIQDBG_SCHED, "NYT:SEND"); -- fiq_queue_request(channel, !(hfnum.b.frnum & 1)); -- } -- else -- { -- // Schedule non-periodic access for next frame (the odd-even bit doesn't effect NP) -- complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1); -- fiq_print(FIQDBG_SCHED, "NYT%04d%d", complete_sched[channel]/8, complete_sched[channel]%8); -- } -- hcint_saved[channel].b.chhltd = 0; -- hcint_saved[channel].b.nyet = 0; -- } -- else -- { -- queued_port[channel] = 0; -- fiq_print(FIQDBG_ERR, "NYETERR2"); -- //BUG(); -- } -- } -- } -- else -- { -- /* -- * If we have any of NAK, ACK, Datatlgerr active on a -- * non-split channel, the sole reason is to reset error -- * counts for a previously broken transaction. The FIQ -- * will thrash on NAK IN and ACK OUT in particular so -- * handle it "once" and allow the IRQ to do the rest. -- */ -- hcint.d32 &= hcintmsk.d32; -- if(hcint.b.nak) -- { -- hcintmsk.b.nak = 0; -- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); -- } -- if (hcint.b.ack) -- { -- hcintmsk.b.ack = 0; -- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); -- } -- } -- -- // Clear the interrupt, this will also clear the HAINT bit -- FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32); -- return hcint_saved[channel].d32 == 0; --} -- --gintsts_data_t gintsts; --gintmsk_data_t gintmsk; --// triggered: The set of interrupts that were triggered --// handled: The set of interrupts that have been handled (no IRQ is --// required) --// keep: The set of interrupts we want to keep unmasked even though we --// want to trigger an IRQ to handle it (SOF and HCINTR) --gintsts_data_t triggered, handled, keep; --hfnum_data_t hfnum; -- --void __attribute__ ((naked)) notrace dwc_otg_hcd_handle_fiq(void) --{ -- -- /* entry takes care to store registers we will be treading on here */ -- asm __volatile__ ( -- "mov ip, sp ;" -- /* stash FIQ and normal regs */ -- "stmdb sp!, {r0-r12, lr};" -- /* !! THIS SETS THE FRAME, adjust to > sizeof locals */ -- "sub fp, ip, #512 ;" -- ); -- -- // Cannot put local variables at the beginning of the function -- // because otherwise 'C' will play with the stack pointer. any locals -- // need to be inside the following block -- do -- { -- fiq_done++; -- gintsts.d32 = FIQ_READ(dwc_regs_base + 0x14); -- gintmsk.d32 = FIQ_READ(dwc_regs_base + 0x18); -- hfnum.d32 = FIQ_READ(dwc_regs_base + 0x408); -- triggered.d32 = gintsts.d32 & gintmsk.d32; -- handled.d32 = 0; -- keep.d32 = 0; -- fiq_print(FIQDBG_INT, "FIQ "); -- fiq_print(FIQDBG_INT, "%08x", gintsts.d32); -- fiq_print(FIQDBG_INT, "%08x", gintmsk.d32); -- if(gintsts.d32) -- { -- // If port enabled -- if((FIQ_READ(dwc_regs_base + 0x440) & 0xf) == 0x5) -- { -- if(gintsts.b.sofintr) -- { -- if(fiq_sof_handle(hfnum)) -- { -- handled.b.sofintr = 1; /* Handled in FIQ */ -- } -- else -- { -- /* Keer interrupt unmasked */ -- keep.b.sofintr = 1; -- } -- { -- // Need to make sure the read and clearing of the SOF interrupt is as close as possible to avoid the possibility of missing -- // a start of frame interrupt -- gintsts_data_t gintsts = { .b.sofintr = 1 }; -- FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32); -- } -- } -- -- if(fiq_split_enable && gintsts.b.hcintr) -- { -- int i; -- haint_data_t haint; -- haintmsk_data_t haintmsk; -- -- haint.d32 = FIQ_READ(dwc_regs_base + 0x414); -- haintmsk.d32 = FIQ_READ(dwc_regs_base + 0x418); -- haint.d32 &= haintmsk.d32; -- haint_saved.d32 |= haint.d32; -- -- fiq_print(FIQDBG_INT, "hcintr"); -- fiq_print(FIQDBG_INT, "%08x", FIQ_READ(dwc_regs_base + 0x414)); -- -- // Go through each channel that has an enabled interrupt -- for(i = 0; i < 16; i++) -- if((haint.d32 >> i) & 1) -- if(fiq_hcintr_handle(i, hfnum)) -- haint_saved.d32 &= ~(1 << i); /* this was handled */ -- -- /* If we've handled all host channel interrupts then don't trigger the interrupt */ -- if(haint_saved.d32 == 0) -- { -- handled.b.hcintr = 1; -- } -- else -- { -- /* Make sure we keep the channel interrupt unmasked when triggering the IRQ */ -- keep.b.hcintr = 1; -- } -- -- { -- gintsts_data_t gintsts = { .b.hcintr = 1 }; -- -- // Always clear the channel interrupt -- FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32); -- } -- } -- } -- else -- { -- last_sof = -1; -- } -- } -- -- // Mask out the interrupts triggered - those handled - don't mask out the ones we want to keep -- gintmsk.d32 = keep.d32 | (gintmsk.d32 & ~(triggered.d32 & ~handled.d32)); -- // Save those that were triggered but not handled -- gintsts_saved.d32 |= triggered.d32 & ~handled.d32; -- FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); -- -- // Clear and save any unhandled interrupts and trigger the interrupt -- if(gintsts_saved.d32) -- { -- /* To enable the MPHI interrupt (INT 32) -- */ -- FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send); -- FIQ_WRITE( c_mphi_regs.outddb, (1 << 29)); -- -- mphi_int_count++; -- } -- } -- while(0); -- -- mb(); -- -- /* exit back to normal mode restoring everything */ -- asm __volatile__ ( -- /* return FIQ regs back to pristine state -- * and get normal regs back -- */ -- "ldmia sp!, {r0-r12, lr};" -- -- /* return */ -- "subs pc, lr, #4;" -- ); --} -- - /** This function handles interrupts for the HCD. */ - int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - { - int retval = 0; - static int last_time; -- - dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; - gintsts_data_t gintsts; - gintmsk_data_t gintmsk; - hfnum_data_t hfnum; -+ haintmsk_data_t haintmsk; - - #ifdef DEBUG - dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; -@@ -517,14 +100,25 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - /* Check if HOST Mode */ - if (dwc_otg_is_host_mode(core_if)) { - local_fiq_disable(); -- gintmsk.d32 |= gintsts_saved.d32; -- gintsts.d32 |= gintsts_saved.d32; -- gintsts_saved.d32 = 0; -+ /* Pull in from the FIQ's disabled mask */ -+ gintmsk.d32 = gintmsk.d32 | ~(dwc_otg_hcd->fiq_state->gintmsk_saved.d32); -+ dwc_otg_hcd->fiq_state->gintmsk_saved.d32 = ~0; -+ -+ -+ if (fiq_fsm_enable && ( 0x0000FFFF & ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint))) { -+ gintsts.b.hcintr = 1; -+ } -+ -+ /* Danger will robinson: fake a SOF if necessary */ -+ if (fiq_fsm_enable && (dwc_otg_hcd->fiq_state->gintmsk_saved.b.sofintr == 1)) { -+ gintsts.b.sofintr = 1; -+ } -+ gintsts.d32 &= gintmsk.d32; -+ - local_fiq_enable(); - if (!gintsts.d32) { - goto exit_handler_routine; - } -- gintsts.d32 &= gintmsk.d32; - - #ifdef DEBUG - // We should be OK doing this because the common interrupts should already have been serviced -@@ -544,12 +138,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - gintsts.d32, core_if); - #endif - hfnum.d32 = DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum); -- if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) -- { -- /* Note, we should never get here if the FIQ is doing it's job properly*/ -- retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); -- } -- else if (gintsts.b.sofintr) { -+ if (gintsts.b.sofintr) { - retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); - } - -@@ -604,37 +193,43 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - } - - exit_handler_routine: -- -- if (fiq_fix_enable) -- { -+ if (fiq_enable) { -+ gintmsk_data_t gintmsk_new; -+ haintmsk_data_t haintmsk_new; - local_fiq_disable(); -- // Make sure that we don't clear the interrupt if we've still got pending work to do -- if(gintsts_saved.d32 == 0) -- { -- /* Clear the MPHI interrupt */ -- DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16)); -- if (mphi_int_count >= 60) -- { -- DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16))); -- while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17))) -- ; -- DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); -- mphi_int_count = 0; -- } -- int_done++; -+ gintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->gintmsk_saved.d32; -+ if(fiq_fsm_enable) -+ haintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->haintmsk_saved.d32; -+ else -+ haintmsk_new.d32 = 0x0000FFFF; -+ -+ /* The FIQ could have sneaked another interrupt in. If so, don't clear MPHI */ -+ if ((gintmsk_new.d32 == ~0) && (haintmsk_new.d32 == 0x0000FFFF)) { -+ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.intstat, (1<<16)); -+ if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) { -+ fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR"); -+ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, ((1<<31) + (1<<16))); -+ while (!(DWC_READ_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & (1 << 17))) -+ ; -+ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, (1<<31)); -+ dwc_otg_hcd->fiq_state->mphi_int_count = 0; -+ } -+ int_done++; - } -- -- // Unmask handled interrupts -- FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); -- //DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1); -- -+ haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk); -+ /* Re-enable interrupts that the FIQ masked (first time round) */ -+ FIQ_WRITE(dwc_otg_hcd->fiq_state->dwc_regs_base + GINTMSK, gintmsk.d32); - local_fiq_enable(); - -- if((jiffies / HZ) > last_time) -- { -+ if ((jiffies / HZ) > last_time) { -+ //dwc_otg_qh_t *qh; -+ //dwc_list_link_t *cur; - /* Once a second output the fiq and irq numbers, useful for debug */ - last_time = jiffies / HZ; -- DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done); -+ // DWC_WARN("np_kick=%d AHC=%d sched_frame=%d cur_frame=%d int_done=%d fiq_done=%d", -+ // dwc_otg_hcd->fiq_state->kick_np_queues, dwc_otg_hcd->available_host_channels, -+ // dwc_otg_hcd->fiq_state->next_sched_frame, hfnum.b.frnum, int_done, dwc_otg_hcd->fiq_state->fiq_done); -+ //printk(KERN_WARNING "Periodic queues:\n"); - } - } - -@@ -686,6 +281,7 @@ static inline void track_missed_sofs(uint16_t curr_frame_number) - int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) - { - hfnum_data_t hfnum; -+ gintsts_data_t gintsts = { .d32 = 0 }; - dwc_list_link_t *qh_entry; - dwc_otg_qh_t *qh; - dwc_otg_transaction_type_e tr_type; -@@ -733,7 +329,7 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) - } - } - -- g_next_sched_frame = next_sched_frame; -+ hcd->fiq_state->next_sched_frame = next_sched_frame; - - tr_type = dwc_otg_hcd_select_transactions(hcd); - if (tr_type != DWC_OTG_TRANSACTION_NONE) { -@@ -741,10 +337,11 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) - did_something = 1; - } - -- /* Clear interrupt */ -- gintsts.b.sofintr = 1; -- DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); -- -+ /* Clear interrupt - but do not trample on the FIQ sof */ -+ if (!fiq_fsm_enable) { -+ gintsts.b.sofintr = 1; -+ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); -+ } - return 1; - } - -@@ -1020,19 +617,21 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd) - { - int i; - int retval = 0; -- haint_data_t haint; -+ haint_data_t haint = { .d32 = 0 } ; - - /* Clear appropriate bits in HCINTn to clear the interrupt bit in - * GINTSTS */ - -- haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); -+ if (!fiq_fsm_enable) -+ haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); - - // Overwrite with saved interrupts from fiq handler -- if(fiq_split_enable) -+ if(fiq_fsm_enable) - { -+ /* check the mask? */ - local_fiq_disable(); -- haint.d32 = haint_saved.d32; -- haint_saved.d32 = 0; -+ haint.b2.chint |= ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint); -+ dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint = ~0; - local_fiq_enable(); - } - -@@ -1076,9 +675,7 @@ static uint32_t get_actual_xfer_length(dwc_hc_t * hc, - *short_read = (hctsiz.b.xfersize != 0); - } - } else if (hc->qh->do_split) { -- if(fiq_split_enable) -- length = split_out_xfersize[hc->hc_num]; -- else -+ //length = split_out_xfersize[hc->hc_num]; - length = qtd->ssplit_out_xfer_count; - } else { - length = hc->xfer_len; -@@ -1325,19 +922,17 @@ static void release_channel(dwc_otg_hcd_t * hcd, - int free_qtd; - dwc_irqflags_t flags; - dwc_spinlock_t *channel_lock = hcd->channel_lock; --#ifdef FIQ_DEBUG -- int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0; --#endif -+ - int hog_port = 0; - - DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", - __func__, hc->hc_num, halt_status, hc->xfer_len); - -- if(fiq_split_enable && hc->do_split) { -+ if(fiq_fsm_enable && hc->do_split) { - if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) { - if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID || - hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) { -- hog_port = 1; -+ hog_port = 0; - } - } - } -@@ -1394,6 +989,8 @@ static void release_channel(dwc_otg_hcd_t * hcd, - * function clears the channel interrupt enables and conditions, so - * there's no need to clear the Channel Halted interrupt separately. - */ -+ if (fiq_fsm_enable && hcd->fiq_state->channel[hc->hc_num].fsm != FIQ_PASSTHROUGH) -+ dwc_otg_cleanup_fiq_channel(hcd, hc->hc_num); - dwc_otg_hc_cleanup(hcd->core_if, hc); - DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); - -@@ -1416,27 +1013,10 @@ static void release_channel(dwc_otg_hcd_t * hcd, - - DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); - hcd->available_host_channels++; -- fiq_print(FIQDBG_PORTHUB, "AHC = %d ", hcd->available_host_channels); -+ fiq_print(FIQDBG_INT, hcd->fiq_state, "AHC = %d ", hcd->available_host_channels); - DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); - } - -- if(fiq_split_enable && hc->do_split) -- { -- if(!(hcd->hub_port[hc->hub_addr] & (1 << hc->port_addr))) -- { -- fiq_print(FIQDBG_ERR, "PRTNOTAL"); -- //BUG(); -- } -- if(!hog_port && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC || -- hc->ep_type == DWC_OTG_EP_TYPE_INTR)) { -- hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); --#ifdef FIQ_DEBUG -- hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; --#endif -- fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); -- } -- } -- - /* Try to queue more transfers now that there's a free channel. */ - tr_type = dwc_otg_hcd_select_transactions(hcd); - if (tr_type != DWC_OTG_TRANSACTION_NONE) { -@@ -1858,7 +1438,7 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, - switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { - case UE_BULK: - case UE_CONTROL: -- if (nak_holdoff_enable) -+ if (nak_holdoff && qtd->qh->do_split) - hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd); - } - -@@ -2074,7 +1654,7 @@ static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd, - // With the FIQ running we only ever see the failed NYET - if (dwc_full_frame_num(frnum) != - dwc_full_frame_num(hc->qh->sched_frame) || -- fiq_split_enable) { -+ fiq_fsm_enable) { - /* - * No longer in the same full speed frame. - * Treat this as a transaction error. -@@ -2460,12 +2040,11 @@ static inline int halt_status_ok(dwc_otg_hcd_t * hcd, - static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - dwc_hc_t * hc, - dwc_otg_hc_regs_t * hc_regs, -- dwc_otg_qtd_t * qtd, -- hcint_data_t hcint, -- hcintmsk_data_t hcintmsk) -+ dwc_otg_qtd_t * qtd) - { - int out_nak_enh = 0; -- -+ hcint_data_t hcint; -+ hcintmsk_data_t hcintmsk; - /* For core with OUT NAK enhancement, the flow for high- - * speed CONTROL/BULK OUT is handled a little differently. - */ -@@ -2495,11 +2074,9 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - } - - /* Read the HCINTn register to determine the cause for the halt. */ -- if(!fiq_split_enable) -- { -- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -- hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); -- } -+ -+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -+ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); - - if (hcint.b.xfercomp) { - /** @todo This is here because of a possible hardware bug. Spec -@@ -2624,15 +2201,13 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, - static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, - dwc_hc_t * hc, - dwc_otg_hc_regs_t * hc_regs, -- dwc_otg_qtd_t * qtd, -- hcint_data_t hcint, -- hcintmsk_data_t hcintmsk) -+ dwc_otg_qtd_t * qtd) - { - DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " - "Channel Halted--\n", hc->hc_num); - - if (hcd->core_if->dma_enable) { -- handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd, hcint, hcintmsk); -+ handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd); - } else { - #ifdef DEBUG - if (!halt_status_ok(hcd, hc, hc_regs, qtd)) { -@@ -2645,11 +2220,368 @@ static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, - return 1; - } - -+ -+/** -+ * dwc_otg_fiq_unmangle_isoc() - Update the iso_frame_desc structure on -+ * FIQ transfer completion -+ * @hcd: Pointer to dwc_otg_hcd struct -+ * @num: Host channel number -+ * -+ * 1. Un-mangle the status as recorded in each iso_frame_desc status -+ * 2. Copy it from the dwc_otg_urb into the real URB -+ */ -+void dwc_otg_fiq_unmangle_isoc(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num) -+{ -+ struct dwc_otg_hcd_urb *dwc_urb = qtd->urb; -+ int nr_frames = dwc_urb->packet_count; -+ int i; -+ hcint_data_t frame_hcint; -+ -+ for (i = 0; i < nr_frames; i++) { -+ frame_hcint.d32 = dwc_urb->iso_descs[i].status; -+ if (frame_hcint.b.xfercomp) { -+ dwc_urb->iso_descs[i].status = 0; -+ dwc_urb->actual_length += dwc_urb->iso_descs[i].actual_length; -+ } else if (frame_hcint.b.frmovrun) { -+ if (qh->ep_is_in) -+ dwc_urb->iso_descs[i].status = -DWC_E_NO_STREAM_RES; -+ else -+ dwc_urb->iso_descs[i].status = -DWC_E_COMMUNICATION; -+ dwc_urb->error_count++; -+ dwc_urb->iso_descs[i].actual_length = 0; -+ } else if (frame_hcint.b.xacterr) { -+ dwc_urb->iso_descs[i].status = -DWC_E_PROTOCOL; -+ dwc_urb->error_count++; -+ dwc_urb->iso_descs[i].actual_length = 0; -+ } else if (frame_hcint.b.bblerr) { -+ dwc_urb->iso_descs[i].status = -DWC_E_OVERFLOW; -+ dwc_urb->error_count++; -+ dwc_urb->iso_descs[i].actual_length = 0; -+ } else { -+ /* Something went wrong */ -+ dwc_urb->iso_descs[i].status = -1; -+ dwc_urb->iso_descs[i].actual_length = 0; -+ dwc_urb->error_count++; -+ } -+ } -+ //printk_ratelimited(KERN_INFO "%s: HS isochronous of %d/%d frames with %d errors complete\n", -+ // __FUNCTION__, i, dwc_urb->packet_count, dwc_urb->error_count); -+ hcd->fops->complete(hcd, dwc_urb->priv, dwc_urb, 0); -+ release_channel(hcd, qh->channel, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -+} -+ -+/** -+ * dwc_otg_fiq_unsetup_per_dma() - Remove data from bounce buffers for split transactions -+ * @hcd: Pointer to dwc_otg_hcd struct -+ * @num: Host channel number -+ * -+ * Copies data from the FIQ bounce buffers into the URB's transfer buffer. Does not modify URB state. -+ * Returns total length of data or -1 if the buffers were not used. -+ * -+ */ -+int dwc_otg_fiq_unsetup_per_dma(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num) -+{ -+ dwc_hc_t *hc = qh->channel; -+ struct fiq_dma_blob *blob = hcd->fiq_dmab; -+ struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; -+ uint8_t *ptr = NULL; -+ int index = 0, len = 0; -+ int i = 0; -+ if (hc->ep_is_in) { -+ /* Copy data out of the DMA bounce buffers to the URB's buffer. -+ * The align_buf is ignored as this is ignored on FSM enqueue. */ -+ ptr = qtd->urb->buf; -+ if (qh->ep_type == UE_ISOCHRONOUS) { -+ /* Isoc IN transactions - grab the offset of the iso_frame_desc into the URB transfer buffer */ -+ index = qtd->isoc_frame_index; -+ ptr += qtd->urb->iso_descs[index].offset; -+ } else { -+ /* Need to increment by actual_length for interrupt IN */ -+ ptr += qtd->urb->actual_length; -+ } -+ -+ for (i = 0; i < st->dma_info.index; i++) { -+ len += st->dma_info.slot_len[i]; -+ dwc_memcpy(ptr, &blob->channel[num].index[i].buf[0], st->dma_info.slot_len[i]); -+ ptr += st->dma_info.slot_len[i]; -+ } -+ return len; -+ } else { -+ /* OUT endpoints - nothing to do. */ -+ return -1; -+ } -+ -+} -+/** -+ * dwc_otg_hcd_handle_hc_fsm() - handle an unmasked channel interrupt -+ * from a channel handled in the FIQ -+ * @hcd: Pointer to dwc_otg_hcd struct -+ * @num: Host channel number -+ * -+ * If a host channel interrupt was received by the IRQ and this was a channel -+ * used by the FIQ, the execution flow for transfer completion is substantially -+ * different from the normal (messy) path. This function and its friends handles -+ * channel cleanup and transaction completion from a FIQ transaction. -+ */ -+int32_t dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd_t *hcd, uint32_t num) -+{ -+ struct fiq_channel_state *st = &hcd->fiq_state->channel[num]; -+ dwc_hc_t *hc = hcd->hc_ptr_array[num]; -+ dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); -+ dwc_otg_qh_t *qh = hc->qh; -+ dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[num]; -+ hcint_data_t hcint = hcd->fiq_state->channel[num].hcint_copy; -+ int hostchannels = 0; -+ int ret = 0; -+ fiq_print(FIQDBG_INT, hcd->fiq_state, "OUT %01d %01d ", num , st->fsm); -+ -+ hostchannels = hcd->available_host_channels; -+ switch (st->fsm) { -+ case FIQ_TEST: -+ break; -+ -+ case FIQ_DEQUEUE_ISSUED: -+ /* hc_halt was called. QTD no longer exists. */ -+ /* TODO: for a nonperiodic split transaction, need to issue a -+ * CLEAR_TT_BUFFER hub command if we were in the start-split phase. -+ */ -+ release_channel(hcd, hc, NULL, hc->halt_status); -+ ret = 1; -+ break; -+ -+ case FIQ_NP_SPLIT_DONE: -+ /* Nonperiodic transaction complete. */ -+ if (!hc->ep_is_in) { -+ qtd->ssplit_out_xfer_count = hc->xfer_len; -+ } -+ if (hcint.b.xfercomp) { -+ handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd); -+ } else if (hcint.b.nak) { -+ handle_hc_nak_intr(hcd, hc, hc_regs, qtd); -+ } -+ ret = 1; -+ break; -+ -+ case FIQ_NP_SPLIT_HS_ABORTED: -+ /* A HS abort is a 3-strikes on the HS bus at any point in the transaction. -+ * Normally a CLEAR_TT_BUFFER hub command would be required: we can't do that -+ * because there's no guarantee which order a non-periodic split happened in. -+ * We could end up clearing a perfectly good transaction out of the buffer. -+ */ -+ if (hcint.b.xacterr) { -+ qtd->error_count += st->nr_errors; -+ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); -+ } else if (hcint.b.ahberr) { -+ handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); -+ } else { -+ local_fiq_disable(); -+ BUG(); -+ } -+ break; -+ -+ case FIQ_NP_SPLIT_LS_ABORTED: -+ /* A few cases can cause this - either an unknown state on a SSPLIT or -+ * STALL/data toggle error response on a CSPLIT */ -+ if (hcint.b.stall) { -+ handle_hc_stall_intr(hcd, hc, hc_regs, qtd); -+ } else if (hcint.b.datatglerr) { -+ handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd); -+ } else if (hcint.b.ahberr) { -+ handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); -+ } else { -+ local_fiq_disable(); -+ BUG(); -+ } -+ break; -+ -+ case FIQ_PER_SPLIT_DONE: -+ /* Isoc IN or Interrupt IN/OUT */ -+ -+ /* Flow control here is different from the normal execution by the driver. -+ * We need to completely ignore most of the driver's method of handling -+ * split transactions and do it ourselves. -+ */ -+ if (hc->ep_type == UE_INTERRUPT) { -+ if (hcint.b.nak) { -+ handle_hc_nak_intr(hcd, hc, hc_regs, qtd); -+ } else if (hc->ep_is_in) { -+ int len; -+ len = dwc_otg_fiq_unsetup_per_dma(hcd, hc->qh, qtd, num); -+ //printk(KERN_NOTICE "FIQ Transaction: hc=%d len=%d urb_len = %d\n", num, len, qtd->urb->length); -+ qtd->urb->actual_length += len; -+ if (qtd->urb->actual_length >= qtd->urb->length) { -+ qtd->urb->status = 0; -+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -+ } else { -+ /* Interrupt transfer not complete yet - is it a short read? */ -+ if (len < hc->max_packet) { -+ /* Interrupt transaction complete */ -+ qtd->urb->status = 0; -+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -+ } else { -+ /* Further transactions required */ -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); -+ } -+ } -+ } else { -+ /* Interrupt OUT complete. */ -+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); -+ qtd->urb->actual_length += hc->xfer_len; -+ if (qtd->urb->actual_length >= qtd->urb->length) { -+ qtd->urb->status = 0; -+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -+ } else { -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); -+ } -+ } -+ } else { -+ /* ISOC IN complete. */ -+ struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; -+ int len = 0; -+ /* Record errors, update qtd. */ -+ if (st->nr_errors) { -+ frame_desc->actual_length = 0; -+ frame_desc->status = -DWC_E_PROTOCOL; -+ } else { -+ frame_desc->status = 0; -+ /* Unswizzle dma */ -+ len = dwc_otg_fiq_unsetup_per_dma(hcd, qh, qtd, num); -+ frame_desc->actual_length = len; -+ } -+ qtd->isoc_frame_index++; -+ if (qtd->isoc_frame_index == qtd->urb->packet_count) { -+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -+ } else { -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); -+ } -+ } -+ break; -+ -+ case FIQ_PER_ISO_OUT_DONE: { -+ struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; -+ /* Record errors, update qtd. */ -+ if (st->nr_errors) { -+ frame_desc->actual_length = 0; -+ frame_desc->status = -DWC_E_PROTOCOL; -+ } else { -+ frame_desc->status = 0; -+ frame_desc->actual_length = frame_desc->length; -+ } -+ qtd->isoc_frame_index++; -+ qtd->isoc_split_offset = 0; -+ if (qtd->isoc_frame_index == qtd->urb->packet_count) { -+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -+ } else { -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); -+ } -+ } -+ break; -+ -+ case FIQ_PER_SPLIT_NYET_ABORTED: -+ /* Doh. lost the data. */ -+ printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x frame %d failed " -+ "- FIQ reported NYET. Data may have been lost.\n", -+ hc->dev_addr, hc->ep_num, dwc_otg_hcd_get_frame_number(hcd) >> 3); -+ if (hc->ep_type == UE_ISOCHRONOUS) { -+ struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; -+ /* Record errors, update qtd. */ -+ frame_desc->actual_length = 0; -+ frame_desc->status = -DWC_E_PROTOCOL; -+ qtd->isoc_frame_index++; -+ qtd->isoc_split_offset = 0; -+ if (qtd->isoc_frame_index == qtd->urb->packet_count) { -+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -+ } else { -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); -+ } -+ } else { -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); -+ } -+ break; -+ -+ case FIQ_HS_ISOC_DONE: -+ /* The FIQ has performed a whole pile of isochronous transactions. -+ * The status is recorded as the interrupt state should the transaction -+ * fail. -+ */ -+ dwc_otg_fiq_unmangle_isoc(hcd, qh, qtd, num); -+ break; -+ -+ case FIQ_PER_SPLIT_LS_ABORTED: -+ if (hcint.b.xacterr) { -+ /* Hub has responded with an ERR packet. Device -+ * has been unplugged or the port has been disabled. -+ * TODO: need to issue a reset to the hub port. */ -+ qtd->error_count += 3; -+ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); -+ } else if (hcint.b.stall) { -+ handle_hc_stall_intr(hcd, hc, hc_regs, qtd); -+ } else { -+ printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x failed " -+ "- FIQ reported FSM=%d. Data may have been lost.\n", -+ st->fsm, hc->dev_addr, hc->ep_num); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); -+ } -+ break; -+ -+ case FIQ_PER_SPLIT_HS_ABORTED: -+ /* Either the SSPLIT phase suffered transaction errors or something -+ * unexpected happened. -+ */ -+ qtd->error_count += 3; -+ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); -+ break; -+ -+ case FIQ_PER_SPLIT_TIMEOUT: -+ /* Couldn't complete in the nominated frame */ -+ printk(KERN_INFO "Transfer to device %d endpoint 0x%x frame %d failed " -+ "- FIQ timed out. Data may have been lost.\n", -+ hc->dev_addr, hc->ep_num, dwc_otg_hcd_get_frame_number(hcd) >> 3); -+ if (hc->ep_type == UE_ISOCHRONOUS) { -+ struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; -+ /* Record errors, update qtd. */ -+ frame_desc->actual_length = 0; -+ if (hc->ep_is_in) { -+ frame_desc->status = -DWC_E_NO_STREAM_RES; -+ } else { -+ frame_desc->status = -DWC_E_COMMUNICATION; -+ } -+ qtd->isoc_frame_index++; -+ if (qtd->isoc_frame_index == qtd->urb->packet_count) { -+ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); -+ } else { -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE); -+ } -+ } else { -+ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); -+ } -+ break; -+ -+ default: -+ local_fiq_disable(); -+ DWC_WARN("unexpected state received on hc=%d fsm=%d", hc->hc_num, st->fsm); -+ BUG(); -+ } -+ //if (hostchannels != hcd->available_host_channels) { -+ /* should have incremented by now! */ -+ // BUG(); -+// } -+ return ret; -+} -+ - /** Handles interrupt for a specific Host Channel */ - int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - { - int retval = 0; -- hcint_data_t hcint, hcint_orig; -+ hcint_data_t hcint; - hcintmsk_data_t hcintmsk; - dwc_hc_t *hc; - dwc_otg_hc_regs_t *hc_regs; -@@ -2668,24 +2600,32 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - } - qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); - -+ /* -+ * FSM mode: Check to see if this is a HC interrupt from a channel handled by the FIQ. -+ * Execution path is fundamentally different for the channels after a FIQ has completed -+ * a split transaction. -+ */ -+ if (fiq_fsm_enable) { -+ switch (dwc_otg_hcd->fiq_state->channel[num].fsm) { -+ case FIQ_PASSTHROUGH: -+ break; -+ case FIQ_PASSTHROUGH_ERRORSTATE: -+ /* Hook into the error count */ -+ fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "HCDERR%02d", num); -+ if (dwc_otg_hcd->fiq_state->channel[num].nr_errors) { -+ qtd->error_count = 0; -+ fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "RESET "); -+ } -+ break; -+ default: -+ dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd, num); -+ return 1; -+ } -+ } -+ - hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); -- hcint_orig = hcint; - hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); -- DWC_DEBUGPL(DBG_HCDV, -- " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", -- hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); - hcint.d32 = hcint.d32 & hcintmsk.d32; -- -- if(fiq_split_enable) -- { -- // replace with the saved interrupts from the fiq handler -- local_fiq_disable(); -- hcint_orig.d32 = hcint_saved[num].d32; -- hcint.d32 = hcint_orig.d32 & hcintmsk_saved[num].d32; -- hcint_saved[num].d32 = 0; -- local_fiq_enable(); -- } -- - if (!dwc_otg_hcd->core_if->dma_enable) { - if (hcint.b.chhltd && hcint.d32 != 0x2) { - hcint.b.chhltd = 0; -@@ -2703,7 +2643,7 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) - hcint.b.nyet = 0; - } - if (hcint.b.chhltd) { -- retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd, hcint_orig, hcintmsk_saved[num]); -+ retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd); - } - if (hcint.b.ahberr) { - retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index ee8eec9..dc27b24 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -58,6 +58,7 @@ - #else - #include - #endif -+#include - - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) - #define USB_URB_EP_LINKING 1 -@@ -69,7 +70,8 @@ - #include "dwc_otg_dbg.h" - #include "dwc_otg_driver.h" - #include "dwc_otg_hcd.h" --#include "dwc_otg_mphi_fix.h" -+ -+extern unsigned char _dwc_otg_fiq_stub, _dwc_otg_fiq_stub_end; - - /** - * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is -@@ -80,7 +82,7 @@ - - static const char dwc_otg_hcd_name[] = "dwc_otg_hcd"; - --extern bool fiq_fix_enable; -+extern bool fiq_enable; - - /** @name Linux HC Driver API Functions */ - /** @{ */ -@@ -351,7 +353,6 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, - urb); - } - } -- - DWC_FREE(dwc_otg_urb); - if (!new_entry) { - DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n"); -@@ -395,13 +396,9 @@ static struct dwc_otg_hcd_function_ops hcd_fops = { - static struct fiq_handler fh = { - .name = "usb_fiq", - }; --struct fiq_stack_s { -- int magic1; -- uint8_t stack[2048]; -- int magic2; --} fiq_stack; - --extern mphi_regs_t c_mphi_regs; -+ -+ - /** - * Initializes the HCD. This function allocates memory for and initializes the - * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the -@@ -433,20 +430,6 @@ int hcd_init(dwc_bus_dev_t *_dev) - pci_set_consistent_dma_mask(_dev, dmamask); - #endif - -- if (fiq_fix_enable) -- { -- // Set up fiq -- claim_fiq(&fh); -- set_fiq_handler(__FIQ_Branch, 4); -- memset(®s,0,sizeof(regs)); -- regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq; -- regs.ARM_r9 = (long)0; -- regs.ARM_sp = (long)fiq_stack.stack + sizeof(fiq_stack.stack) - 4; -- set_fiq_regs(®s); -- fiq_stack.magic1 = 0xdeadbeef; -- fiq_stack.magic2 = 0xaa995566; -- } -- - /* - * Allocate memory for the base HCD plus the DWC OTG HCD. - * Initialize the base HCD. -@@ -466,30 +449,7 @@ int hcd_init(dwc_bus_dev_t *_dev) - - hcd->regs = otg_dev->os_dep.base; - -- if (fiq_fix_enable) -- { -- volatile extern void *dwc_regs_base; -- -- //Set the mphi periph to the required registers -- c_mphi_regs.base = otg_dev->os_dep.mphi_base; -- c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; -- c_mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28; -- c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; -- c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; -- -- dwc_regs_base = otg_dev->os_dep.base; - -- //Enable mphi peripheral -- writel((1<<31),c_mphi_regs.ctrl); --#ifdef DEBUG -- if (readl(c_mphi_regs.ctrl) & 0x80000000) -- DWC_DEBUGPL(DBG_USER, "MPHI periph has been enabled\n"); -- else -- DWC_DEBUGPL(DBG_USER, "MPHI periph has NOT been enabled\n"); --#endif -- // Enable FIQ interrupt from USB peripheral -- enable_fiq(INTERRUPT_VC_USB); -- } - /* Initialize the DWC OTG HCD. */ - dwc_otg_hcd = dwc_otg_hcd_alloc_hcd(); - if (!dwc_otg_hcd) { -@@ -503,6 +463,55 @@ int hcd_init(dwc_bus_dev_t *_dev) - goto error2; - } - -+ if (fiq_enable) -+ { -+ if (claim_fiq(&fh)) { -+ DWC_ERROR("Can't claim FIQ"); -+ goto error2; -+ } -+ -+ DWC_WARN("FIQ at 0x%08x", (fiq_fsm_enable ? (int)&dwc_otg_fiq_fsm : (int)&dwc_otg_fiq_nop)); -+ DWC_WARN("FIQ ASM at 0x%08x length %d", (int)&_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub)); -+ -+ set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub); -+ memset(®s,0,sizeof(regs)); -+ -+ regs.ARM_r8 = (long) dwc_otg_hcd->fiq_state; -+ if (fiq_fsm_enable) { -+ regs.ARM_r9 = dwc_otg_hcd->core_if->core_params->host_channels; -+ //regs.ARM_r10 = dwc_otg_hcd->dma; -+ regs.ARM_fp = (long) dwc_otg_fiq_fsm; -+ } else { -+ regs.ARM_fp = (long) dwc_otg_fiq_nop; -+ } -+ -+ regs.ARM_sp = (long) dwc_otg_hcd->fiq_stack + (sizeof(struct fiq_stack) - 4); -+ -+// __show_regs(®s); -+ set_fiq_regs(®s); -+ -+ //Set the mphi periph to the required registers -+ dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base; -+ dwc_otg_hcd->fiq_state->mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; -+ dwc_otg_hcd->fiq_state->mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28; -+ dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; -+ dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; -+ dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base; -+ DWC_WARN("MPHI regs_base at 0x%08x", (int)dwc_otg_hcd->fiq_state->mphi_regs.base); -+ //Enable mphi peripheral -+ writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl); -+#ifdef DEBUG -+ if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000) -+ DWC_WARN("MPHI periph has been enabled"); -+ else -+ DWC_WARN("MPHI periph has NOT been enabled"); -+#endif -+ // Enable FIQ interrupt from USB peripheral -+ enable_fiq(INTERRUPT_VC_USB); -+ local_fiq_enable(); -+ } -+ -+ - otg_dev->hcd->otg_dev = otg_dev; - hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel) -@@ -617,9 +626,13 @@ void hcd_stop(struct usb_hcd *hcd) - /** Returns the current frame number. */ - static int get_frame_number(struct usb_hcd *hcd) - { -+ hprt0_data_t hprt0; - dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); -- -- return dwc_otg_hcd_get_frame_number(dwc_otg_hcd); -+ hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0); -+ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) -+ return dwc_otg_hcd_get_frame_number(dwc_otg_hcd) >> 3; -+ else -+ return dwc_otg_hcd_get_frame_number(dwc_otg_hcd); - } - - #ifdef DEBUG -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index db95851..4d5a24c 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -41,7 +41,6 @@ - - #include "dwc_otg_hcd.h" - #include "dwc_otg_regs.h" --#include "dwc_otg_mphi_fix.h" - - extern bool microframe_schedule; - -@@ -576,7 +575,6 @@ static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - } - - --extern int g_next_sched_frame, g_np_count, g_np_sent; - - /** - * Schedules an interrupt or isochronous transfer in the periodic schedule. -@@ -636,9 +634,9 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry); - } - else { -- if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, g_next_sched_frame)) -+ if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, hcd->fiq_state->next_sched_frame)) - { -- g_next_sched_frame = qh->sched_frame; -+ hcd->fiq_state->next_sched_frame = qh->sched_frame; - - } - /* Always start in the inactive schedule. */ -@@ -679,7 +677,7 @@ int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - /* Always start in the inactive schedule. */ - DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive, - &qh->qh_list_entry); -- g_np_count++; -+ //hcd->fiq_state->kick_np_queues = 1; - } else { - status = schedule_periodic(hcd, qh); - if ( !hcd->periodic_qh_count ) { -@@ -739,13 +737,12 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - hcd->non_periodic_qh_ptr->next; - } - DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); -- -- // If we've removed the last non-periodic entry then there are none left! -- g_np_count = g_np_sent; -+ //if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive)) -+ // hcd->fiq_state->kick_np_queues = 1; - } else { - deschedule_periodic(hcd, qh); - hcd->periodic_qh_count--; -- if( !hcd->periodic_qh_count ) { -+ if( !hcd->periodic_qh_count && !fiq_fsm_enable ) { - intr_mask.b.sofintr = 1; - DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, - intr_mask.d32, 0); -@@ -770,28 +767,11 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, - int sched_next_periodic_split) - { - if (dwc_qh_is_non_per(qh)) { -- -- dwc_otg_qh_t *qh_tmp; -- dwc_list_link_t *qh_list; -- DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) -- { -- qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); -- if(qh_tmp == qh) -- { -- /* -- * FIQ is being disabled because this one nevers gets a np_count increment -- * This is still not absolutely correct, but it should fix itself with -- * just an unnecessary extra interrupt -- */ -- g_np_sent = g_np_count; -- } -- } -- -- - dwc_otg_hcd_qh_remove(hcd, qh); - if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { - /* Add back to inactive non-periodic schedule. */ - dwc_otg_hcd_qh_add(hcd, qh); -+ //hcd->fiq_state->kick_np_queues = 1; - } - } else { - uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd); -@@ -850,9 +830,9 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, - DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, - &qh->qh_list_entry); - } else { -- if(!dwc_frame_num_le(g_next_sched_frame, qh->sched_frame)) -+ if(!dwc_frame_num_le(hcd->fiq_state->next_sched_frame, qh->sched_frame)) - { -- g_next_sched_frame = qh->sched_frame; -+ hcd->fiq_state->next_sched_frame = qh->sched_frame; - } - - DWC_LIST_MOVE_HEAD -@@ -943,6 +923,9 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, - if (*qh == NULL) { - retval = -DWC_E_NO_MEMORY; - goto done; -+ } else { -+ if (fiq_enable) -+ hcd->fiq_state->kick_np_queues = 1; - } - } - retval = dwc_otg_hcd_qh_add(hcd, *qh); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c -deleted file mode 100755 -index 50b94a8..0000000 ---- a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c -+++ /dev/null -@@ -1,113 +0,0 @@ --#include "dwc_otg_regs.h" --#include "dwc_otg_dbg.h" -- --void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name) --{ -- DWC_DEBUGPL(DBG_USER, "*** Debugging from within the %s function: ***\n" -- "curmode: %1i Modemismatch: %1i otgintr: %1i sofintr: %1i\n" -- "rxstsqlvl: %1i nptxfempty : %1i ginnakeff: %1i goutnakeff: %1i\n" -- "ulpickint: %1i i2cintr: %1i erlysuspend:%1i usbsuspend: %1i\n" -- "usbreset: %1i enumdone: %1i isooutdrop: %1i eopframe: %1i\n" -- "restoredone: %1i epmismatch: %1i inepint: %1i outepintr: %1i\n" -- "incomplisoin:%1i incomplisoout:%1i fetsusp: %1i resetdet: %1i\n" -- "portintr: %1i hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i\n" -- "conidstschng:%1i disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", -- function_name, -- gintsts.b.curmode, -- gintsts.b.modemismatch, -- gintsts.b.otgintr, -- gintsts.b.sofintr, -- gintsts.b.rxstsqlvl, -- gintsts.b.nptxfempty, -- gintsts.b.ginnakeff, -- gintsts.b.goutnakeff, -- gintsts.b.ulpickint, -- gintsts.b.i2cintr, -- gintsts.b.erlysuspend, -- gintsts.b.usbsuspend, -- gintsts.b.usbreset, -- gintsts.b.enumdone, -- gintsts.b.isooutdrop, -- gintsts.b.eopframe, -- gintsts.b.restoredone, -- gintsts.b.epmismatch, -- gintsts.b.inepint, -- gintsts.b.outepintr, -- gintsts.b.incomplisoin, -- gintsts.b.incomplisoout, -- gintsts.b.fetsusp, -- gintsts.b.resetdet, -- gintsts.b.portintr, -- gintsts.b.hcintr, -- gintsts.b.ptxfempty, -- gintsts.b.lpmtranrcvd, -- gintsts.b.conidstschng, -- gintsts.b.disconnect, -- gintsts.b.sessreqintr, -- gintsts.b.wkupintr); -- return; --} -- --void dwc_debug_core_int_mask(gintmsk_data_t gintmsk, const char* function_name) --{ -- DWC_DEBUGPL(DBG_USER, "Interrupt Mask status (called from %s) :\n" -- "modemismatch: %1i otgintr: %1i sofintr: %1i rxstsqlvl: %1i\n" -- "nptxfempty: %1i ginnakeff: %1i goutnakeff: %1i ulpickint: %1i\n" -- "i2cintr: %1i erlysuspend:%1i usbsuspend: %1i usbreset: %1i\n" -- "enumdone: %1i isooutdrop: %1i eopframe: %1i restoredone: %1i\n" -- "epmismatch: %1i inepintr: %1i outepintr: %1i incomplisoin:%1i\n" -- "incomplisoout:%1i fetsusp: %1i resetdet: %1i portintr: %1i\n" -- "hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i conidstschng:%1i\n" -- "disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", -- function_name, -- gintmsk.b.modemismatch, -- gintmsk.b.otgintr, -- gintmsk.b.sofintr, -- gintmsk.b.rxstsqlvl, -- gintmsk.b.nptxfempty, -- gintmsk.b.ginnakeff, -- gintmsk.b.goutnakeff, -- gintmsk.b.ulpickint, -- gintmsk.b.i2cintr, -- gintmsk.b.erlysuspend, -- gintmsk.b.usbsuspend, -- gintmsk.b.usbreset, -- gintmsk.b.enumdone, -- gintmsk.b.isooutdrop, -- gintmsk.b.eopframe, -- gintmsk.b.restoredone, -- gintmsk.b.epmismatch, -- gintmsk.b.inepintr, -- gintmsk.b.outepintr, -- gintmsk.b.incomplisoin, -- gintmsk.b.incomplisoout, -- gintmsk.b.fetsusp, -- gintmsk.b.resetdet, -- gintmsk.b.portintr, -- gintmsk.b.hcintr, -- gintmsk.b.ptxfempty, -- gintmsk.b.lpmtranrcvd, -- gintmsk.b.conidstschng, -- gintmsk.b.disconnect, -- gintmsk.b.sessreqintr, -- gintmsk.b.wkupintr); -- return; --} -- --void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name) --{ -- DWC_DEBUGPL(DBG_USER, "otg int register (from %s function):\n" -- "sesenddet:%1i sesreqsucstschung:%2i hstnegsucstschng:%1i\n" -- "hstnegdet:%1i adevtoutchng: %2i debdone: %1i\n" -- "mvic: %1i\n", -- function_name, -- gotgint.b.sesenddet, -- gotgint.b.sesreqsucstschng, -- gotgint.b.hstnegsucstschng, -- gotgint.b.hstnegdet, -- gotgint.b.adevtoutchng, -- gotgint.b.debdone, -- gotgint.b.mvic); -- -- return; --} -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -deleted file mode 100755 -index ca17379..0000000 ---- a/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h -+++ /dev/null -@@ -1,48 +0,0 @@ --#ifndef __DWC_OTG_MPHI_FIX_H__ --#define __DWC_OTG_MPHI_FIX_H__ --#define FIQ_WRITE(_addr_,_data_) (*(volatile uint32_t *) (_addr_) = (_data_)) --#define FIQ_READ(_addr_) (*(volatile uint32_t *) (_addr_)) -- --typedef struct { -- volatile void* base; -- volatile void* ctrl; -- volatile void* outdda; -- volatile void* outddb; -- volatile void* intstat; --} mphi_regs_t; -- --void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name); --void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name); --void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); -- --extern gintsts_data_t gintsts_saved; -- --#ifdef DEBUG --#define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__) --#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) dwc_debug_core_int_mask(_arg_,__func__) --#define DWC_DBG_PRINT_OTG_INT(_arg_) dwc_debug_otg_int(_arg_,__func__) -- --#else --#define DWC_DBG_PRINT_CORE_INT(_arg_) --#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) --#define DWC_DBG_PRINT_OTG_INT(_arg_) -- --#endif -- --typedef enum { -- FIQDBG_SCHED = (1 << 0), -- FIQDBG_INT = (1 << 1), -- FIQDBG_ERR = (1 << 2), -- FIQDBG_PORTHUB = (1 << 3), --} FIQDBG_T; -- --void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...); --#ifdef FIQ_DEBUG --#define fiq_print _fiq_print --#else --#define fiq_print(x, y, ...) --#endif -- --extern bool fiq_fix_enable, nak_holdoff_enable, fiq_split_enable; -- --#endif --- -1.9.3 - - -From 469fd1e539f06b9daa205b0c075e185229d2f3dc Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 1 May 2014 13:38:17 +0100 -Subject: [PATCH 101/124] config: enable CONFIG_DMA_CMA - it may fix cache - coherency issue in USB driver - -See: https://github.com/raspberrypi/linux/issues/575 ---- - arch/arm/configs/bcmrpi_defconfig | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index f0a5370..0d1cb49 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -381,6 +381,8 @@ CONFIG_NFC=m - CONFIG_NFC_PN533=m - CONFIG_DEVTMPFS=y - CONFIG_DEVTMPFS_MOUNT=y -+CONFIG_DMA_CMA=y -+CONFIG_CMA_SIZE_MBYTES=5 - CONFIG_BLK_DEV_LOOP=y - CONFIG_BLK_DEV_CRYPTOLOOP=m - CONFIG_BLK_DEV_DRBD=m --- -1.9.3 - - -From 450940a1bbf20725425dff533d3fc9b4c39679bf Mon Sep 17 00:00:00 2001 -From: P33M -Date: Sat, 3 May 2014 15:22:14 +0100 -Subject: [PATCH 102/124] fiq_fsm: fix dequeues for non-periodic split - transactions - -If a dequeue happened between the SSPLIT and CSPLIT phases of the -transaction, the HCD would never receive an interrupt. ---- - drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 1 + - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 8 +++++--- - 2 files changed, 6 insertions(+), 3 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -index 61f5534..e8ea868 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -@@ -625,6 +625,7 @@ static int notrace noinline fiq_fsm_do_sof(struct fiq_state *state, int num_chan - break; - - case FIQ_PER_SPLIT_TIMEOUT: -+ case FIQ_DEQUEUE_ISSUED: - /* Ugly: we have to force a HCD interrupt. - * Poke the mask for the channel in question. - * We will take a fake SOF because of this, but -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index e6b4a1e..4009f22 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -614,11 +614,13 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, - /* In FIQ FSM mode, we need to shut down carefully. - * The FIQ may attempt to restart a disabled channel */ - if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) { -+ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE; -+ qh->channel->halt_pending = 1; - hcd->fiq_state->channel[n].fsm = FIQ_DEQUEUE_ISSUED; -+ } else { -+ dwc_otg_hc_halt(hcd->core_if, qh->channel, -+ DWC_OTG_HC_XFER_URB_DEQUEUE); - } -- dwc_otg_hc_halt(hcd->core_if, qh->channel, -- DWC_OTG_HC_XFER_URB_DEQUEUE); -- - } - } - --- -1.9.3 - - -From 78af09acbbccfefa661af7b1b44920c65f229d77 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 13 May 2014 00:40:42 +0100 -Subject: [PATCH 103/124] fiq_fsm: Disable by default - ---- - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index bbf63a4..144bbf8 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -243,7 +243,7 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { - //Global variable to switch the fiq fix on or off - bool fiq_enable = 1; - // Global variable to enable the split transaction fix --bool fiq_fsm_enable = true; -+bool fiq_fsm_enable = false; - //Bulk split-transaction NAK holdoff in microframes - uint16_t nak_holdoff = 8; - --- -1.9.3 - - -From f01d97062f47a9b1a855fde79cca55c6fa801885 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 7 Jan 2014 12:36:07 +0000 -Subject: [PATCH 104/124] V4L2: Increase the MMAL timeout to 3sec - -MJPEG codec flush is now taking longer and results -in a kernel panic if the driver has stopped waiting for -the result when it finally completes. -Increase the timeout value from 1 to 3secs. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/mmal-vchiq.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/platform/bcm2835/mmal-vchiq.c b/drivers/media/platform/bcm2835/mmal-vchiq.c -index 82752e6..76f249e 100644 ---- a/drivers/media/platform/bcm2835/mmal-vchiq.c -+++ b/drivers/media/platform/bcm2835/mmal-vchiq.c -@@ -742,7 +742,7 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, - return ret; - } - -- ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, HZ); -+ ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, 3*HZ); - if (ret <= 0) { - pr_err("error %d waiting for sync completion\n", ret); - if (ret == 0) --- -1.9.3 - - -From 8f7ef9b1bd08f636e09b413d8a90d624fb125293 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Thu, 15 May 2014 14:56:56 +0100 -Subject: [PATCH 105/124] fiq_fsm: Handle HC babble errors - -The HCTSIZ transfer size field raises a babble interrupt if -the counter wraps. Handle the resulting interrupt in this case. ---- - drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 14 +++++--------- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 4 ++++ - 2 files changed, 9 insertions(+), 9 deletions(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -index e8ea868..7aad7f7 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -@@ -773,7 +773,7 @@ static int notrace noinline fiq_fsm_do_hcintr(struct fiq_state *state, int num_c - handled = 1; - restart = 1; - } -- } else if (hcint.b.stall) { -+ } else if (hcint.b.stall || hcint.b.bblerr) { - /* A STALL implies either a LS bus error or a genuine STALL. */ - st->fsm = FIQ_NP_SPLIT_LS_ABORTED; - } else { -@@ -925,7 +925,7 @@ static int notrace noinline fiq_fsm_do_hcintr(struct fiq_state *state, int num_c - } else if (hcint.b.nyet) { - /* Doh. Data lost. */ - st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; -- } else if (hcint.b.xacterr || hcint.b.stall) { -+ } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { - st->fsm = FIQ_PER_SPLIT_LS_ABORTED; - } else { - st->fsm = FIQ_PER_SPLIT_HS_ABORTED; -@@ -962,12 +962,11 @@ static int notrace noinline fiq_fsm_do_hcintr(struct fiq_state *state, int num_c - } else if (hcint.b.nyet) { - st->fsm = FIQ_PER_SPLIT_NYET_ABORTED; - start_next_periodic = 1; -- } else if (hcint.b.xacterr) { -+ } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { - /* Local 3-strikes retry is handled by the core. This is a ERR response.*/ - st->fsm = FIQ_PER_SPLIT_LS_ABORTED; - } else { -- fiq_print(FIQDBG_INT, state, "TOGGLES"); -- BUG(); -+ st->fsm = FIQ_PER_SPLIT_HS_ABORTED; - } - break; - -@@ -1006,12 +1005,9 @@ static int notrace noinline fiq_fsm_do_hcintr(struct fiq_state *state, int num_c - st->fsm = FIQ_PER_SPLIT_DONE; - } - } -- } else if (hcint.b.xacterr || hcint.b.stall) { -+ } else if (hcint.b.xacterr || hcint.b.stall || hcint.b.bblerr) { - /* For xacterr, Local 3-strikes retry is handled by the core. This is a ERR response.*/ - st->fsm = FIQ_PER_SPLIT_LS_ABORTED; -- } else if (hcint.b.datatglerr) { -- fiq_print(FIQDBG_INT, state, "TOGGLES"); -- BUG(); - } else { - st->fsm = FIQ_PER_SPLIT_HS_ABORTED; - } -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index be8ef1b..f9acef2 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -2386,6 +2386,8 @@ int32_t dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd_t *hcd, uint32_t num) - handle_hc_stall_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.datatglerr) { - handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd); -+ } else if (hcint.b.bblerr) { -+ handle_hc_babble_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.ahberr) { - handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); - } else { -@@ -2522,6 +2524,8 @@ int32_t dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd_t *hcd, uint32_t num) - handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); - } else if (hcint.b.stall) { - handle_hc_stall_intr(hcd, hc, hc_regs, qtd); -+ } else if (hcint.b.bblerr) { -+ handle_hc_babble_intr(hcd, hc, hc_regs, qtd); - } else { - printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x failed " - "- FIQ reported FSM=%d. Data may have been lost.\n", --- -1.9.3 - - -From 3191347dff37f521fb392b865d064c748b116e24 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 12 May 2014 15:12:02 +0100 -Subject: [PATCH 106/124] vchiq: Avoid high load when blocked and unkillable - ---- - .../interface/vchiq_arm/vchiq_2835_arm.c | 1 + - .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 1 + - .../interface/vchiq_arm/vchiq_connected.c | 1 + - .../vc04_services/interface/vchiq_arm/vchiq_core.c | 1 + - .../interface/vchiq_arm/vchiq_kern_lib.c | 1 + - .../interface/vchiq_arm/vchiq_killable.h | 69 ++++++++++++++++++++++ - .../vc04_services/interface/vchiq_arm/vchiq_util.c | 1 + - 7 files changed, 75 insertions(+) - create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h - -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -index b3bdaa2..7e7b09f 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -@@ -56,6 +56,7 @@ - #include "vchiq_arm.h" - #include "vchiq_2835.h" - #include "vchiq_connected.h" -+#include "vchiq_killable.h" - - #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2) - -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c -index c1fb8c3..99c8967 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -49,6 +49,7 @@ - #include "vchiq_core.h" - #include "vchiq_ioctl.h" - #include "vchiq_arm.h" -+#include "vchiq_killable.h" - - #define DEVICE_NAME "vchiq" - -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c -index 65f4b52..5efc62f 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c -@@ -33,6 +33,7 @@ - - #include "vchiq_connected.h" - #include "vchiq_core.h" -+#include "vchiq_killable.h" - #include - #include - -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c -index f35ed4f..71ed0a5 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c -@@ -32,6 +32,7 @@ - */ - - #include "vchiq_core.h" -+#include "vchiq_killable.h" - - #define VCHIQ_SLOT_HANDLER_STACK 8192 - -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c -index be9735f..5a4182e 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c -@@ -39,6 +39,7 @@ - - #include "vchiq_core.h" - #include "vchiq_arm.h" -+#include "vchiq_killable.h" - - /* ---- Public Variables ------------------------------------------------- */ - -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h -new file mode 100644 -index 0000000..505ee1a ---- /dev/null -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h -@@ -0,0 +1,69 @@ -+/** -+ * Copyright (c) 2010-2012 Broadcom. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions, and the following disclaimer, -+ * without modification. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The names of the above-listed copyright holders may not be used -+ * to endorse or promote products derived from this software without -+ * specific prior written permission. -+ * -+ * ALTERNATIVELY, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2, as published by the Free -+ * Software Foundation. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef VCHIQ_KILLABLE_H -+#define VCHIQ_KILLABLE_H -+ -+#include -+#include -+ -+#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT)) -+ -+static inline int __must_check down_interruptible_killable(struct semaphore *sem) -+{ -+ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */ -+ int ret; -+ sigset_t blocked, oldset; -+ siginitsetinv(&blocked, SHUTDOWN_SIGS); -+ sigprocmask(SIG_SETMASK, &blocked, &oldset); -+ ret = down_interruptible(sem); -+ sigprocmask(SIG_SETMASK, &oldset, NULL); -+ return ret; -+} -+#define down_interruptible down_interruptible_killable -+ -+ -+static inline int __must_check mutex_lock_interruptible_killable(struct mutex *lock) -+{ -+ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */ -+ int ret; -+ sigset_t blocked, oldset; -+ siginitsetinv(&blocked, SHUTDOWN_SIGS); -+ sigprocmask(SIG_SETMASK, &blocked, &oldset); -+ ret = mutex_lock_interruptible(lock); -+ sigprocmask(SIG_SETMASK, &oldset, NULL); -+ return ret; -+} -+#define mutex_lock_interruptible mutex_lock_interruptible_killable -+ -+#endif -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c -index c2eefef..05e7979 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c -@@ -32,6 +32,7 @@ - */ - - #include "vchiq_util.h" -+#include "vchiq_killable.h" - - static inline int is_pow2(int i) - { --- -1.9.3 - - -From 5912d175eed845782861dc2ef467319795c5459d Mon Sep 17 00:00:00 2001 -From: cbeytas -Date: Mon, 24 Jun 2013 00:05:40 -0400 -Subject: [PATCH 107/124] Perform I2C combined transactions when possible - -Perform I2C combined transactions whenever possible, within the -restrictions of the Broadcomm Serial Controller. - -Disable DONE interrupt during TA poll - -Prevent interrupt from being triggered if poll is missed and transfer -starts and finishes. ---- - drivers/i2c/busses/i2c-bcm2708.c | 25 ++++++++++++++++++++++++- - 1 file changed, 24 insertions(+), 1 deletion(-) - -diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c -index 98bc4e7..3758024 100644 ---- a/drivers/i2c/busses/i2c-bcm2708.c -+++ b/drivers/i2c/busses/i2c-bcm2708.c -@@ -150,7 +150,7 @@ static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi) - static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi) - { - unsigned long bus_hz; -- u32 cdiv; -+ u32 cdiv, s; - u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1; - - bus_hz = clk_get_rate(bi->clk); -@@ -164,6 +164,29 @@ static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi) - bcm2708_wr(bi, BSC_DIV, cdiv); - bcm2708_wr(bi, BSC_A, bi->msg->addr); - bcm2708_wr(bi, BSC_DLEN, bi->msg->len); -+ /* Do the next two messages meet combined transaction criteria? -+ - Current message is a write, next message is a read -+ - Both messages to same slave address -+ - Write message can fit inside FIFO (16 bytes or less) */ -+ if ( (bi->nmsgs > 1) && -+ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) && -+ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) { -+ /* Fill FIFO with entire write message (16 byte FIFO) */ -+ while (bi->pos < bi->msg->len) -+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]); -+ /* Start write transfer (no interrupts, don't clear FIFO) */ -+ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST); -+ /* poll for transfer start bit (should only take 1-20 polls) */ -+ do { -+ s = bcm2708_rd(bi, BSC_S); -+ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE))); -+ /* Send next read message before the write transfer finishes. */ -+ bi->nmsgs--; -+ bi->msg++; -+ bi->pos = 0; -+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len); -+ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ; -+ } - bcm2708_wr(bi, BSC_C, c); - } - --- -1.9.3 - - -From 83705e536745384f1adf21fd46c3b05fa2214b9a Mon Sep 17 00:00:00 2001 -From: brabl2 -Date: Sat, 21 Dec 2013 21:25:36 +0100 -Subject: [PATCH 108/124] i2c-bcm2708: fixed baudrate - -Fixed issue where the wrong CDIV value was set for baudrates below 3815 Hz (for 250MHz bus clock). In that case the computed CDIV value was more than 0xffff. However the CDIV register width is only 16 bits. This resulted in incorrect setting of CDIV and higher baudrate than intended. -Example: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0x1704 -> 42430Hz -After correction: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0xffff -> 3815Hz -The correct baudrate is shown in the log after the cdiv > 0xffff correction. ---- - drivers/i2c/busses/i2c-bcm2708.c | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c -index 3758024..fbf502a 100644 ---- a/drivers/i2c/busses/i2c-bcm2708.c -+++ b/drivers/i2c/busses/i2c-bcm2708.c -@@ -155,6 +155,8 @@ static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi) - - bus_hz = clk_get_rate(bi->clk); - cdiv = bus_hz / baudrate; -+ if (cdiv > 0xffff) -+ cdiv = 0xffff; - - if (bi->msg->flags & I2C_M_RD) - c |= BSC_C_INTR | BSC_C_READ; -@@ -291,6 +293,8 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) - struct clk *clk; - struct bcm2708_i2c *bi; - struct i2c_adapter *adap; -+ unsigned long bus_hz; -+ u32 cdiv; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) { -@@ -366,8 +370,15 @@ static int bcm2708_i2c_probe(struct platform_device *pdev) - goto out_free_irq; - } - -- dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %dk)\n", -- pdev->id, (unsigned long)regs->start, irq, baudrate/1000); -+ bus_hz = clk_get_rate(bi->clk); -+ cdiv = bus_hz / baudrate; -+ if (cdiv > 0xffff) { -+ cdiv = 0xffff; -+ baudrate = bus_hz / cdiv; -+ } -+ -+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", -+ pdev->id, (unsigned long)regs->start, irq, baudrate); - - return 0; - --- -1.9.3 - - -From 4a3bd8dd29c49241b098f681ee4832fcb9d838b0 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 19 May 2014 13:02:07 +0100 -Subject: [PATCH 109/124] V4L2: Add support for setting H264_I_PERIOD - -Adds support for the parameter V4L2_CID_MPEG_VIDEO_H264_I_PERIOD -to set the frequency with which I frames are produced. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.h | 2 +- - drivers/media/platform/bcm2835/controls.c | 7 +++++++ - 2 files changed, 8 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index 4ddd687..3c57b1e 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.h -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h -@@ -15,7 +15,7 @@ - * core driver device - */ - --#define V4L2_CTRL_COUNT 27 /* number of v4l controls */ -+#define V4L2_CTRL_COUNT 28 /* number of v4l controls */ - - enum { - MMAL_COMPONENT_CAMERA = 0, -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index 9a40bd0..95c7647 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -1149,6 +1149,13 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - &ctrl_set_scene_mode, - false - }, -+ { -+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, MMAL_CONTROL_TYPE_STD, -+ 1, 1000, 60, 1, NULL, -+ MMAL_PARAMETER_INTRAPERIOD, -+ &ctrl_set_video_encode_param_output, -+ false -+ }, - }; - - int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev) --- -1.9.3 - - -From e7a85c6aea584f7aa6f30cd7fc8fe91ea4bb88e1 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 12 Feb 2014 11:41:46 +0000 -Subject: [PATCH 110/124] V4L2: Enable GPU function for removing padding from - images. - -GPU can now support arbitrary strides, although may require -additional processing to achieve it. Enable this feature -so that the images delivered are the size requested. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 88 ++++++++++++++++-------- - drivers/media/platform/bcm2835/bcm2835-camera.h | 1 + - drivers/media/platform/bcm2835/controls.c | 4 +- - drivers/media/platform/bcm2835/mmal-parameters.h | 3 +- - 4 files changed, 64 insertions(+), 32 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 3dea993..d3a9075 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -804,20 +804,13 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - f->fmt.pix.height = dev->capture.height; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.pixelformat = dev->capture.fmt->fourcc; -- f->fmt.pix.bytesperline = -- (f->fmt.pix.width * dev->capture.fmt->depth) >> 3; -- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; -- if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG -- && f->fmt.pix.sizeimage < (100 << 10)) { -- /* Need a minimum size for JPEG to account for EXIF. */ -- f->fmt.pix.sizeimage = (100 << 10); -- } -+ f->fmt.pix.bytesperline = dev->capture.stride; -+ f->fmt.pix.sizeimage = dev->capture.buffersize; - -- if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_YUYV || -- dev->capture.fmt->fourcc == V4L2_PIX_FMT_UYVY) -- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; -- else -+ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24) - f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; -+ else -+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; - - v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix, -@@ -841,21 +834,35 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - } - - f->fmt.pix.field = V4L2_FIELD_NONE; -- /* image must be a multiple of 32 pixels wide and 16 lines high */ -- v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 5, -- &f->fmt.pix.height, 32, MAX_HEIGHT, 4, 0); -- f->fmt.pix.bytesperline = (f->fmt.pix.width * mfmt->depth) >> 3; -- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; -- if (f->fmt.pix.sizeimage < MIN_BUFFER_SIZE) -+ -+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -+ "Clipping/aligning %dx%d format %08X\n", -+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); -+ -+ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 1, -+ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 1, 0); -+ f->fmt.pix.bytesperline = (f->fmt.pix.width * mfmt->depth)>>3; -+ -+ /* Image buffer has to be padded to allow for alignment, even though -+ * we then remove that padding before delivering the buffer. -+ */ -+ f->fmt.pix.sizeimage = ((f->fmt.pix.height+15)&~15) * -+ (((f->fmt.pix.width+31)&~31) * mfmt->depth) >> 3; -+ -+ if ((mfmt->flags & V4L2_FMT_FLAG_COMPRESSED) && -+ f->fmt.pix.sizeimage < MIN_BUFFER_SIZE) - f->fmt.pix.sizeimage = MIN_BUFFER_SIZE; - -- if (mfmt->fourcc == V4L2_PIX_FMT_YUYV || -- mfmt->fourcc == V4L2_PIX_FMT_UYVY) -- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; -- else -+ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24) - f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; -+ else -+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; - -+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -+ "Now %dx%d format %08X\n", -+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); -+ - v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix, - __func__); - return 0; -@@ -990,7 +997,9 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - - if (ret) { - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -- "%s failed to set format\n", __func__); -+ "%s failed to set format %dx%d %08X\n", __func__, -+ f->fmt.pix.width, f->fmt.pix.height, -+ f->fmt.pix.pixelformat); - /* ensure capture is not going to be tried */ - dev->capture.port = NULL; - } else { -@@ -1047,8 +1056,12 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - if (ret) - v4l2_dbg(1, bcm2835_v4l2_debug, - &dev->v4l2_dev, -- "%s failed to set format\n", -- __func__); -+ "%s failed to set format %dx%d fmt %08X\n", -+ __func__, -+ f->fmt.pix.width, -+ f->fmt.pix.height, -+ f->fmt.pix.pixelformat -+ ); - } - - if (!ret) { -@@ -1098,6 +1111,7 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - dev->capture.stride = f->fmt.pix.bytesperline; - dev->capture.width = camera_port->es.video.crop.width; - dev->capture.height = camera_port->es.video.crop.height; -+ dev->capture.buffersize = port->current_buffer.size; - - /* select port for capture */ - dev->capture.port = port; -@@ -1105,10 +1119,10 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - dev->capture.encode_component = encode_component; - v4l2_dbg(1, bcm2835_v4l2_debug, - &dev->v4l2_dev, -- "Set dev->capture.fmt %08X, %dx%d, stride %d", -+ "Set dev->capture.fmt %08X, %dx%d, stride %d, size %d", - port->format.encoding, - dev->capture.width, dev->capture.height, -- dev->capture.stride); -+ dev->capture.stride, dev->capture.buffersize); - } - } - -@@ -1347,6 +1361,7 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) - { - int ret; - struct mmal_es_format *format; -+ u32 bool_true = 1; - - ret = vchiq_mmal_init(&dev->instance); - if (ret < 0) -@@ -1401,6 +1416,12 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) - format->es->video.frame_rate.num = 0; /* Rely on fps_range */ - format->es->video.frame_rate.den = 1; - -+ vchiq_mmal_port_parameter_set(dev->instance, -+ &dev->component[MMAL_COMPONENT_CAMERA]-> -+ output[MMAL_CAMERA_PORT_VIDEO], -+ MMAL_PARAMETER_NO_IMAGE_PADDING, -+ &bool_true, sizeof(bool_true)); -+ - format = - &dev->component[MMAL_COMPONENT_CAMERA]-> - output[MMAL_CAMERA_PORT_CAPTURE].format; -@@ -1424,6 +1445,12 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev) - dev->capture.enc_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; - dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; - -+ vchiq_mmal_port_parameter_set(dev->instance, -+ &dev->component[MMAL_COMPONENT_CAMERA]-> -+ output[MMAL_CAMERA_PORT_CAPTURE], -+ MMAL_PARAMETER_NO_IMAGE_PADDING, -+ &bool_true, sizeof(bool_true)); -+ - /* get the preview component ready */ - ret = vchiq_mmal_component_init( - dev->instance, "ril.video_render", -@@ -1554,9 +1581,9 @@ static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev, - static struct v4l2_format default_v4l2_format = { - .fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG, - .fmt.pix.width = 1024, -- .fmt.pix.bytesperline = 1024 * 3 / 2, -+ .fmt.pix.bytesperline = 1024, - .fmt.pix.height = 768, -- .fmt.pix.sizeimage = 1<<18, -+ .fmt.pix.sizeimage = 1024*768, - }; - - static int __init bm2835_mmal_init(void) -@@ -1619,6 +1646,9 @@ static int __init bm2835_mmal_init(void) - if (ret < 0) - goto unreg_dev; - -+ /* Really want to call vidioc_s_fmt_vid_cap with the default -+ * format, but currently the APIs don't join up. -+ */ - ret = mmal_setup_components(dev, &default_v4l2_format); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.h b/drivers/media/platform/bcm2835/bcm2835-camera.h -index 3c57b1e..7fe9f65 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.h -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.h -@@ -70,6 +70,7 @@ struct bm2835_mmal_dev { - unsigned int width; /* width */ - unsigned int height; /* height */ - unsigned int stride; /* stride */ -+ unsigned int buffersize; /* buffer size with padding */ - struct mmal_fmt *fmt; - struct v4l2_fract timeperframe; - -diff --git a/drivers/media/platform/bcm2835/controls.c b/drivers/media/platform/bcm2835/controls.c -index 95c7647..dd1186b 100644 ---- a/drivers/media/platform/bcm2835/controls.c -+++ b/drivers/media/platform/bcm2835/controls.c -@@ -966,8 +966,8 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { - }, - /* { - 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL -- }, --*/ { -+ }, */ -+ { - V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU, - ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL, - MMAL_PARAMETER_EXPOSURE_MODE, -diff --git a/drivers/media/platform/bcm2835/mmal-parameters.h b/drivers/media/platform/bcm2835/mmal-parameters.h -index 089f949..aa0fd18 100644 ---- a/drivers/media/platform/bcm2835/mmal-parameters.h -+++ b/drivers/media/platform/bcm2835/mmal-parameters.h -@@ -57,7 +57,8 @@ enum mmal_parameter_common_type { - MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */ - MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */ - MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */ -- MMAL_PARAMETER_SYSTEM_TIME /**< MMAL_PARAMETER_UINT64_T */ -+ MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */ -+ MMAL_PARAMETER_NO_IMAGE_PADDING /**< MMAL_PARAMETER_BOOLEAN_T */ - }; - - /* camera parameters */ --- -1.9.3 - - -From 8fe35786539a93adc51be2a0afa871098b7ea6fd Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 9 Apr 2014 14:47:17 +0100 -Subject: [PATCH 111/124] V4L2: Add support for V4L2_PIX_FMT_BGR32 - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index d3a9075..56c017f 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -147,6 +147,14 @@ static struct mmal_fmt formats[] = { - .depth = 12, - .mmal_component = MMAL_COMPONENT_CAMERA, - }, -+ { -+ .name = "RGB32 (BE)", -+ .fourcc = V4L2_PIX_FMT_BGR32, -+ .flags = 0, -+ .mmal = MMAL_ENCODING_BGRA, -+ .depth = 32, -+ .mmal_component = MMAL_COMPONENT_CAMERA, -+ }, - }; - - static struct mmal_fmt *get_format(struct v4l2_format *f) --- -1.9.3 - - -From d325383b642d99c9b9921ad4d5aef6d5f128c1d9 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 19 May 2014 15:24:26 +0100 -Subject: [PATCH 112/124] V4L2: Set the colourspace to avoid odd YUV-RGB - conversions - -Removes the amiguity from the conversion routines and stops -them dropping back to the SD vs HD choice of coeffs. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 1 + - drivers/media/platform/bcm2835/mmal-encodings.h | 33 +++++++++++++++++++++++++ - 2 files changed, 34 insertions(+) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 56c017f..c644dec 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -953,6 +953,7 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - camera_port->es.video.crop.height = f->fmt.pix.height; - camera_port->es.video.frame_rate.num = 0; - camera_port->es.video.frame_rate.den = 1; -+ camera_port->es.video.color_space = MMAL_COLOR_SPACE_JPEG_JFIF; - - ret = vchiq_mmal_port_set_format(dev->instance, camera_port); - -diff --git a/drivers/media/platform/bcm2835/mmal-encodings.h b/drivers/media/platform/bcm2835/mmal-encodings.h -index 764bb12..024d620 100644 ---- a/drivers/media/platform/bcm2835/mmal-encodings.h -+++ b/drivers/media/platform/bcm2835/mmal-encodings.h -@@ -12,6 +12,8 @@ - * Simon Mellor - * Luke Diamand - */ -+#ifndef MMAL_ENCODINGS_H -+#define MMAL_ENCODINGS_H - - #define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4') - #define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3') -@@ -92,3 +94,34 @@ - #define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1') - /** Implicitly delineated NAL units without emulation prevention */ - #define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ') -+ -+ -+/** \defgroup MmalColorSpace List of pre-defined video color spaces -+ * This defines a list of common color spaces. This list isn't exhaustive and -+ * is only provided as a convenience to avoid clients having to use FourCC -+ * codes directly. However components are allowed to define and use their own -+ * FourCC codes. -+ */ -+/* @{ */ -+ -+/** Unknown color space */ -+#define MMAL_COLOR_SPACE_UNKNOWN 0 -+/** ITU-R BT.601-5 [SDTV] */ -+#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1') -+/** ITU-R BT.709-3 [HDTV] */ -+#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9') -+/** JPEG JFIF */ -+#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I') -+/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */ -+#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C') -+/** Society of Motion Picture and Television Engineers 240M (1999) */ -+#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0') -+/** ITU-R BT.470-2 System M */ -+#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M') -+/** ITU-R BT.470-2 System BG */ -+#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G') -+/** JPEG JFIF, but with 16..255 luma */ -+#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6') -+/* @} MmalColorSpace List */ -+ -+#endif /* MMAL_ENCODINGS_H */ --- -1.9.3 - - -From c21499ad5284dcee29d54e8187d7927220356965 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 20 May 2014 18:45:52 +0100 -Subject: [PATCH 113/124] V4L2: Make video/still threshold a run-time param - -Move the define for at what resolution the driver -switches from a video mode capture to a stills mode -capture to module parameters. - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 20 ++++++++++++++------ - 1 file changed, 14 insertions(+), 6 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index c644dec..95e1810 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -54,6 +54,13 @@ int bcm2835_v4l2_debug; - module_param_named(debug, bcm2835_v4l2_debug, int, 0644); - MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2"); - -+int max_video_width = MAX_VIDEO_MODE_WIDTH; -+int max_video_height = MAX_VIDEO_MODE_HEIGHT; -+module_param(max_video_width, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); -+MODULE_PARM_DESC(max_video_width, "Threshold for video mode"); -+module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); -+MODULE_PARM_DESC(max_video_height, "Threshold for video mode"); -+ - static struct bm2835_mmal_dev *gdev; /* global device data */ - - #define FPS_MIN 1 -@@ -908,8 +915,8 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, - switch (mfmt->mmal_component) { - case MMAL_COMPONENT_CAMERA: - /* Make a further decision on port based on resolution */ -- if (f->fmt.pix.width <= MAX_VIDEO_MODE_WIDTH -- && f->fmt.pix.height <= MAX_VIDEO_MODE_HEIGHT) -+ if (f->fmt.pix.width <= max_video_width -+ && f->fmt.pix.height <= max_video_height) - camera_port = port = - &dev->component[MMAL_COMPONENT_CAMERA]-> - output[MMAL_CAMERA_PORT_VIDEO]; -@@ -1351,8 +1358,8 @@ static int set_camera_parameters(struct vchiq_mmal_instance *instance, - .max_stills_h = MAX_HEIGHT, - .stills_yuv422 = 1, - .one_shot_stills = 1, -- .max_preview_video_w = 1920, -- .max_preview_video_h = 1088, -+ .max_preview_video_w = max_video_width, -+ .max_preview_video_h = max_video_height, - .num_preview_video_frames = 3, - .stills_capture_circular_buffer_height = 0, - .fast_preview_resume = 0, -@@ -1581,8 +1588,9 @@ static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev, - if (ret < 0) - return ret; - -- v4l2_info(vfd->v4l2_dev, "V4L2 device registered as %s\n", -- video_device_node_name(vfd)); -+ v4l2_info(vfd->v4l2_dev, -+ "V4L2 device registered as %s - stills mode > %dx%d\n", -+ video_device_node_name(vfd), max_video_width, max_video_height); - - return 0; - } --- -1.9.3 - - -From 2a408235f3e632612769960a12e72ab004f975e4 Mon Sep 17 00:00:00 2001 +From e85b5776750f69d5d3b323af673acc2dd8f4f80b Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Fri, 2 May 2014 16:13:59 +0100 -Subject: [PATCH 114/124] Move GPIO setup to hw_params. +Subject: [PATCH 52/53] Move GPIO setup to hw_params. This is used to stop the I2S driver from breaking the GPIO setup for other uses of the PCM interface @@ -117062,705 +114138,80 @@ index b25e158..9976571 100644 1.9.3 -From 0640fc91e36a103b7b16a9ad9d717d4af84ba8b9 Mon Sep 17 00:00:00 2001 +From d4782b92cf0a1d557bf9af79fd5e8a0e1189f3d8 Mon Sep 17 00:00:00 2001 From: popcornmix -Date: Mon, 26 May 2014 16:15:48 +0100 -Subject: [PATCH 115/124] config: Add ISL12057 and PCF2127 RTC driver modules +Date: Fri, 9 May 2014 15:45:13 +0100 +Subject: [PATCH 53/53] fb: distinguish physical and bus addresses --- - arch/arm/configs/bcmrpi_defconfig | 2 ++ - 1 file changed, 2 insertions(+) + drivers/video/fbdev/bcm2708_fb.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 0d1cb49..75aa56d 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -918,7 +918,9 @@ CONFIG_RTC_DRV_MAX6900=m - CONFIG_RTC_DRV_RS5C372=m - CONFIG_RTC_DRV_ISL1208=m - CONFIG_RTC_DRV_ISL12022=m -+CONFIG_RTC_DRV_ISL12057=m - CONFIG_RTC_DRV_X1205=m -+CONFIG_RTC_DRV_PCF2127=m - CONFIG_RTC_DRV_PCF8523=m - CONFIG_RTC_DRV_PCF8563=m - CONFIG_RTC_DRV_PCF8583=m --- -1.9.3 - - -From dff468c602527339811f624c8d3b366149498064 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Thu, 22 May 2014 16:42:24 +0100 -Subject: [PATCH 116/124] dwc_otg: fix interrupt registration for fiq_enable=0 - -Additionally make the module parameter conditional for wherever -hcd->fiq_state is touched. ---- - arch/arm/mach-bcm2708/bcm2708.c | 5 +++++ - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 4 ++-- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 22 ++++++++++++---------- - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 19 +++++++++++-------- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 4 ++-- - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 4 ++-- - drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 8 +++++--- - 7 files changed, 39 insertions(+), 27 deletions(-) - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 887f732..0e71ac8 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -326,6 +326,11 @@ static struct resource bcm2708_usb_resources[] = { - .end = IRQ_HOSTPORT, - .flags = IORESOURCE_IRQ, - }, -+ [3] = { -+ .start = IRQ_USB, -+ .end = IRQ_USB, -+ .flags = IORESOURCE_IRQ, -+ }, +diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c +index 798eb52..b3b1e04 100644 +--- a/drivers/video/fbdev/bcm2708_fb.c ++++ b/drivers/video/fbdev/bcm2708_fb.c +@@ -89,6 +89,7 @@ struct bcm2708_fb { + struct dentry *debugfs_dir; + wait_queue_head_t dma_waitq; + struct bcm2708_fb_stats stats; ++ unsigned long fb_bus_address; }; - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index 144bbf8..f2195d2 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -902,9 +902,9 @@ static int dwc_otg_driver_probe( - */ - - #if defined(PLATFORM_INTERFACE) -- devirq = platform_get_irq(_dev, 0); -+ devirq = platform_get_irq(_dev, fiq_enable ? 0 : 1); - #else -- devirq = _dev->irq; -+ devirq = _dev->irq; - #endif - DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n", - devirq); -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -index 4009f22..daea770 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -2016,17 +2016,19 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) - * stop the FIQ from kicking us. We could potentially still have elements here if we - * ran out of host channels. - */ -- if (DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive)) { -+ if (fiq_enable) { -+ if (DWC_LIST_EMPTY(&hcd->non_periodic_sched_inactive)) { - hcd->fiq_state->kick_np_queues = 0; -- } else { -- /* For each entry remaining in the NP inactive queue, -- * if this a NAK'd retransmit then don't set the kick flag. -- */ -- if(nak_holdoff) { -- DWC_LIST_FOREACH(qh_ptr, &hcd->non_periodic_sched_inactive) { -- qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); -- if (qh->nak_frame == 0xFFFF) { -- hcd->fiq_state->kick_np_queues = 1; -+ } else { -+ /* For each entry remaining in the NP inactive queue, -+ * if this a NAK'd retransmit then don't set the kick flag. -+ */ -+ if(nak_holdoff) { -+ DWC_LIST_FOREACH(qh_ptr, &hcd->non_periodic_sched_inactive) { -+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); -+ if (qh->nak_frame == 0xFFFF) { -+ hcd->fiq_state->kick_np_queues = 1; -+ } - } - } - } -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -index f9acef2..d3e2035 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c -@@ -99,11 +99,12 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - DWC_SPINLOCK(dwc_otg_hcd->lock); - /* Check if HOST Mode */ - if (dwc_otg_is_host_mode(core_if)) { -- local_fiq_disable(); -- /* Pull in from the FIQ's disabled mask */ -- gintmsk.d32 = gintmsk.d32 | ~(dwc_otg_hcd->fiq_state->gintmsk_saved.d32); -- dwc_otg_hcd->fiq_state->gintmsk_saved.d32 = ~0; -- -+ if (fiq_enable) { -+ local_fiq_disable(); -+ /* Pull in from the FIQ's disabled mask */ -+ gintmsk.d32 = gintmsk.d32 | ~(dwc_otg_hcd->fiq_state->gintmsk_saved.d32); -+ dwc_otg_hcd->fiq_state->gintmsk_saved.d32 = ~0; -+ } - - if (fiq_fsm_enable && ( 0x0000FFFF & ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint))) { - gintsts.b.hcintr = 1; -@@ -114,8 +115,10 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) - gintsts.b.sofintr = 1; - } - gintsts.d32 &= gintmsk.d32; -+ -+ if (fiq_enable) -+ local_fiq_enable(); - -- local_fiq_enable(); - if (!gintsts.d32) { - goto exit_handler_routine; - } -@@ -328,8 +331,8 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) - } - } - } -- -- hcd->fiq_state->next_sched_frame = next_sched_frame; -+ if (fiq_enable) -+ hcd->fiq_state->next_sched_frame = next_sched_frame; - - tr_type = dwc_otg_hcd_select_transactions(hcd); - if (tr_type != DWC_OTG_TRANSACTION_NONE) { -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -index dc27b24..07b1808 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -527,9 +527,9 @@ int hcd_init(dwc_bus_dev_t *_dev) - * IRQ line, and calls hcd_start method. - */ - #ifdef PLATFORM_INTERFACE -- retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED); -+ retval = usb_add_hcd(hcd, platform_get_irq(_dev, fiq_enable ? 0 : 1), IRQF_SHARED | IRQF_DISABLED); - #else -- retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED); -+ retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED); - #endif - if (retval < 0) { - goto error2; -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -index 4d5a24c..8706a5c 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c -@@ -634,7 +634,7 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) - DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry); - } - else { -- if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, hcd->fiq_state->next_sched_frame)) -+ if(fiq_enable && (DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, hcd->fiq_state->next_sched_frame))) - { - hcd->fiq_state->next_sched_frame = qh->sched_frame; - -@@ -830,7 +830,7 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, - DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, - &qh->qh_list_entry); - } else { -- if(!dwc_frame_num_le(hcd->fiq_state->next_sched_frame, qh->sched_frame)) -+ if(fiq_enable && !dwc_frame_num_le(hcd->fiq_state->next_sched_frame, qh->sched_frame)) - { - hcd->fiq_state->next_sched_frame = qh->sched_frame; - } -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c -index 5d310df..4b32941 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c -@@ -59,6 +59,8 @@ - #include "dwc_otg_driver.h" - #include "dwc_otg_dbg.h" - -+extern bool fiq_enable; -+ - static struct gadget_wrapper { - dwc_otg_pcd_t *pcd; - -@@ -1222,13 +1224,13 @@ int pcd_init(dwc_bus_dev_t *_dev) - */ - #ifdef PLATFORM_INTERFACE - DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", -- platform_get_irq(_dev, 0)); -- retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq, -+ platform_get_irq(_dev, fiq_enable ? 0 : 1)); -+ retval = request_irq(platform_get_irq(_dev, fiq_enable ? 0 : 1), dwc_otg_pcd_irq, - IRQF_SHARED, gadget_wrapper->gadget.name, - otg_dev->pcd); - if (retval != 0) { - DWC_ERROR("request of irq%d failed\n", -- platform_get_irq(_dev, 0)); -+ platform_get_irq(_dev, fiq_enable ? 0 : 1)); - free_wrapper(gadget_wrapper); - return -EBUSY; - } --- -1.9.3 - - -From ac57662848b38ee0e95e8f297d228fd46be4378c Mon Sep 17 00:00:00 2001 -From: P33M -Date: Wed, 28 May 2014 12:02:34 +0100 -Subject: [PATCH 117/124] mach-bcm2708: account for FIQ latency in timer - interrupt setup - -If all of the following happen in a perfect storm: -- A FIQ is taken between readl(stc) and writel(stc + cycles,stc3) -- The timer compare increment is of the order of min_delta_ns -- The FIQ takes longer than the current min_delta_ns value for the timer - (with contended L1 and L2 caches, 1 in 1000 cases) - -Then a stale value will be written to STC3, which will only trigger an -interrupt when STC wraps - in about 71 minutes. - -Check after writing the value that STC hasn't run ahead. ---- - arch/arm/mach-bcm2708/bcm2708.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 0e71ac8..082361c 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -876,9 +876,12 @@ static int timer_set_next_event(unsigned long cycles, - struct clock_event_device *unused) - { - unsigned long stc; -- -- stc = readl(__io_address(ST_BASE + 0x04)); -- writel(stc + cycles, __io_address(ST_BASE + 0x18)); /* stc3 */ -+ do { -+ stc = readl(__io_address(ST_BASE + 0x04)); -+ /* We could take a FIQ here, which may push ST above STC3 */ -+ writel(stc + cycles, __io_address(ST_BASE + 0x18)); -+ } while ((signed long) (readl(__io_address(ST_BASE + 0x04)) - stc) -+ >= (signed long) cycles); - return 0; - } - --- -1.9.3 - - -From d5dfac5c4f4d2fd2a116b3fa4d069bbcd64600a4 Mon Sep 17 00:00:00 2001 -From: Alex J Lennon -Date: Sat, 24 May 2014 20:52:07 +0100 -Subject: [PATCH 118/124] bcm2708: Ensure 1-wire pullup is disabled by default, - and expose as module parameter - -Signed-off-by: Alex J Lennon ---- - arch/arm/mach-bcm2708/bcm2708.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 082361c..95a47fa 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -79,6 +79,8 @@ - - // use GPIO 4 for the one-wire GPIO pin, if enabled - #define W1_GPIO 4 -+// ensure one-wire GPIO pullup is disabled by default -+#define W1_PULLUP -1 - - /* command line parameters */ - static unsigned boardrev, serial; -@@ -87,6 +89,7 @@ static unsigned disk_led_gpio = 16; - static unsigned disk_led_active_low = 1; - static unsigned reboot_part = 0; - static unsigned w1_gpio_pin = W1_GPIO; -+static unsigned w1_gpio_pullup = W1_PULLUP; - - static void __init bcm2708_init_led(void); - -@@ -266,6 +269,7 @@ static struct platform_device bcm2708_dmaman_device = { - #if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) - static struct w1_gpio_platform_data w1_gpio_pdata = { - .pin = W1_GPIO, -+ .ext_pullup_enable_pin = W1_PULLUP, - .is_open_drain = 0, - }; - -@@ -792,6 +796,7 @@ void __init bcm2708_init(void) - #endif - #if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) - w1_gpio_pdata.pin = w1_gpio_pin; -+ w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup; - platform_device_register(&w1_device); - #endif - bcm_register_device(&bcm2708_systemtimer_device); -@@ -1023,3 +1028,4 @@ module_param(disk_led_gpio, uint, 0644); - module_param(disk_led_active_low, uint, 0644); - module_param(reboot_part, uint, 0644); - module_param(w1_gpio_pin, uint, 0644); -+module_param(w1_gpio_pullup, uint, 0644); --- -1.9.3 - - -From 4bc483a63a20cf6fd748455ca39bdb3497ff6d45 Mon Sep 17 00:00:00 2001 -From: Alex J Lennon -Date: Sat, 24 May 2014 23:10:05 +0100 -Subject: [PATCH 119/124] w1-gpio: Add gpiopin module parameter and correctly - free up gpio pull-up pin, if set - -Signed-off-by: Alex J Lennon ---- - drivers/w1/masters/w1-gpio.c | 41 +++++++++++++++++++++++++++++++++-------- - 1 file changed, 33 insertions(+), 8 deletions(-) - -diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c -index f8b769a..b10f9c9 100644 ---- a/drivers/w1/masters/w1-gpio.c -+++ b/drivers/w1/masters/w1-gpio.c -@@ -23,8 +23,14 @@ - #include "../w1.h" - #include "../w1_int.h" - --static int w1_gpio_pullup = 0; -+static int w1_gpio_pullup = -1; -+static int w1_gpio_pullup_orig = -1; - module_param_named(pullup, w1_gpio_pullup, int, 0); -+MODULE_PARM_DESC(pullup, "GPIO pin pullup number"); -+static int w1_gpio_pin = -1; -+static int w1_gpio_pin_orig = -1; -+module_param_named(gpiopin, w1_gpio_pin, int, 0); -+MODULE_PARM_DESC(gpiopin, "GPIO pin number"); - - static u8 w1_gpio_set_pullup(void *data, int delay) - { -@@ -115,14 +121,16 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) - static int w1_gpio_probe(struct platform_device *pdev) - { - struct w1_bus_master *master; -- struct w1_gpio_platform_data *pdata; -+ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; - int err; - -- if (of_have_populated_dt()) { -- err = w1_gpio_probe_dt(pdev); -- if (err < 0) { -- dev_err(&pdev->dev, "Failed to parse DT\n"); -- return err; -+ if(pdata == NULL) { -+ if (of_have_populated_dt()) { -+ err = w1_gpio_probe_dt(pdev); -+ if (err < 0) { -+ dev_err(&pdev->dev, "Failed to parse DT\n"); -+ return err; -+ } - } - } - -@@ -140,6 +148,19 @@ static int w1_gpio_probe(struct platform_device *pdev) - return -ENOMEM; - } - -+ w1_gpio_pin_orig = pdata->pin; -+ w1_gpio_pullup_orig = pdata->ext_pullup_enable_pin; -+ -+ if(gpio_is_valid(w1_gpio_pin)) { -+ pdata->pin = w1_gpio_pin; -+ pdata->ext_pullup_enable_pin = -1; -+ } -+ if(gpio_is_valid(w1_gpio_pullup)) { -+ pdata->ext_pullup_enable_pin = w1_gpio_pullup; -+ } -+ -+ dev_info(&pdev->dev, "gpio pin %d, gpio pullup pin %d\n", pdata->pin, pdata->ext_pullup_enable_pin); -+ - err = devm_gpio_request(&pdev->dev, pdata->pin, "w1"); - if (err) { - dev_err(&pdev->dev, "gpio_request (pin) failed\n"); -@@ -169,12 +190,13 @@ static int w1_gpio_probe(struct platform_device *pdev) - master->set_pullup = w1_gpio_set_pullup; - } - -- if (w1_gpio_pullup) -+ if (gpio_is_valid(w1_gpio_pullup)) { - if (pdata->is_open_drain) - printk(KERN_ERR "w1-gpio 'pullup' option " - "doesn't work with open drain GPIO\n"); + #define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb) +@@ -314,13 +315,15 @@ static int bcm2708_fb_set_par(struct fb_info *info) else - master->bitbang_pullup = w1_gpio_bitbang_pullup; -+ } + fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; - err = w1_add_master_device(master); - if (err) { -@@ -206,6 +228,9 @@ static int w1_gpio_remove(struct platform_device *pdev) - - w1_remove_master_device(master); - -+ pdata->pin = w1_gpio_pin_orig; -+ pdata->ext_pullup_enable_pin = w1_gpio_pullup_orig; -+ - return 0; - } - --- -1.9.3 - - -From b942e0f141a32b21f5e0b49c3a463e8e87611fc4 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 26 May 2014 16:25:54 +0100 -Subject: [PATCH 120/124] i2c: Make combined transactions optional and disabled - by default - ---- - drivers/i2c/busses/i2c-bcm2708.c | 50 ++++++++++++++++++++++------------------ - 1 file changed, 28 insertions(+), 22 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c -index fbf502a..05531db 100644 ---- a/drivers/i2c/busses/i2c-bcm2708.c -+++ b/drivers/i2c/busses/i2c-bcm2708.c -@@ -74,6 +74,9 @@ static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE; - module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - MODULE_PARM_DESC(baudrate, "The I2C baudrate"); - -+static bool combined = false; -+module_param(combined, bool, 0644); -+MODULE_PARM_DESC(combined, "Use combined transactions"); - - struct bcm2708_i2c { - struct i2c_adapter adapter; -@@ -166,28 +169,31 @@ static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi) - bcm2708_wr(bi, BSC_DIV, cdiv); - bcm2708_wr(bi, BSC_A, bi->msg->addr); - bcm2708_wr(bi, BSC_DLEN, bi->msg->len); -- /* Do the next two messages meet combined transaction criteria? -- - Current message is a write, next message is a read -- - Both messages to same slave address -- - Write message can fit inside FIFO (16 bytes or less) */ -- if ( (bi->nmsgs > 1) && -- !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) && -- (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) { -- /* Fill FIFO with entire write message (16 byte FIFO) */ -- while (bi->pos < bi->msg->len) -- bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]); -- /* Start write transfer (no interrupts, don't clear FIFO) */ -- bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST); -- /* poll for transfer start bit (should only take 1-20 polls) */ -- do { -- s = bcm2708_rd(bi, BSC_S); -- } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE))); -- /* Send next read message before the write transfer finishes. */ -- bi->nmsgs--; -- bi->msg++; -- bi->pos = 0; -- bcm2708_wr(bi, BSC_DLEN, bi->msg->len); -- c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ; -+ if (combined) -+ { -+ /* Do the next two messages meet combined transaction criteria? -+ - Current message is a write, next message is a read -+ - Both messages to same slave address -+ - Write message can fit inside FIFO (16 bytes or less) */ -+ if ( (bi->nmsgs > 1) && -+ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) && -+ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) { -+ /* Fill FIFO with entire write message (16 byte FIFO) */ -+ while (bi->pos < bi->msg->len) -+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]); -+ /* Start write transfer (no interrupts, don't clear FIFO) */ -+ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST); -+ /* poll for transfer start bit (should only take 1-20 polls) */ -+ do { -+ s = bcm2708_rd(bi, BSC_S); -+ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE))); -+ /* Send next read message before the write transfer finishes. */ -+ bi->nmsgs--; -+ bi->msg++; -+ bi->pos = 0; -+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len); -+ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ; -+ } ++ fb->fb_bus_address = fbinfo->base; ++ fbinfo->base &= ~0xc0000000; + fb->fb.fix.smem_start = fbinfo->base; + fb->fb.fix.smem_len = fbinfo->pitch * fbinfo->yres_virtual; + fb->fb.screen_size = fbinfo->screen_size; + if (fb->fb.screen_base) + iounmap(fb->fb.screen_base); + fb->fb.screen_base = +- (void *)ioremap_wc(fb->fb.fix.smem_start, fb->fb.screen_size); ++ (void *)ioremap_wc(fbinfo->base, fb->fb.screen_size); + if (!fb->fb.screen_base) { + /* the console may currently be locked */ + console_trylock(); +@@ -331,7 +334,7 @@ static int bcm2708_fb_set_par(struct fb_info *info) } - bcm2708_wr(bi, BSC_C, c); - } --- -1.9.3 - - -From a35dfa97bee2e32aa77f655ddd547c8088f2fcb7 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 27 May 2014 12:58:00 +0100 -Subject: [PATCH 121/124] V4L2: Fix incorrect pool sizing - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 95e1810..8d4dd03 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -1358,8 +1358,10 @@ static int set_camera_parameters(struct vchiq_mmal_instance *instance, - .max_stills_h = MAX_HEIGHT, - .stills_yuv422 = 1, - .one_shot_stills = 1, -- .max_preview_video_w = max_video_width, -- .max_preview_video_h = max_video_height, -+ .max_preview_video_w = (max_video_width > 1920) ? -+ max_video_width : 1920, -+ .max_preview_video_h = (max_video_height > 1088) ? -+ max_video_height : 1088, - .num_preview_video_frames = 3, - .stills_capture_circular_buffer_height = 0, - .fast_preview_resume = 0, --- -1.9.3 - - -From 723f33bc5f8ee5ee76598da27487dfdadd6d7fcc Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 27 May 2014 14:06:12 +0100 -Subject: [PATCH 122/124] V4L2: Add option to disable enum_framesizes. - -Gstreamer's handling of a driver that advertises -V4L2_FRMSIZE_TYPE_STEPWISE to define the supported -resolutions is broken. See bug -https://bugzilla.gnome.org/show_bug.cgi?id=726521 - -Optional parameter of gst_v4l2src_is_broken added. -If non-zero, the driver claims not to support that -ioctl, and gstreamer should be happy again (it -guesses a set of defaults for itself). - -Signed-off-by: Dave Stevenson ---- - drivers/media/platform/bcm2835/bcm2835-camera.c | 59 +++++++++++++++++++++++++ - 1 file changed, 59 insertions(+) - -diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c -index 8d4dd03..c021e74 100644 ---- a/drivers/media/platform/bcm2835/bcm2835-camera.c -+++ b/drivers/media/platform/bcm2835/bcm2835-camera.c -@@ -61,6 +61,19 @@ MODULE_PARM_DESC(max_video_width, "Threshold for video mode"); - module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - MODULE_PARM_DESC(max_video_height, "Threshold for video mode"); - -+/* Gstreamer bug https://bugzilla.gnome.org/show_bug.cgi?id=726521 -+ * v4l2src does bad (and actually wrong) things when the vidioc_enum_framesizes -+ * function says type V4L2_FRMSIZE_TYPE_STEPWISE, which we do by default. -+ * It's happier if we just don't say anything at all, when it then -+ * sets up a load of defaults that it thinks might work. -+ * If gst_v4l2src_is_broken is non-zero, then we remove the function from -+ * our function table list (actually switch to an alternate set, but same -+ * result). -+ */ -+int gst_v4l2src_is_broken = 0; -+module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); -+MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer"); -+ - static struct bm2835_mmal_dev *gdev; /* global device data */ - - #define FPS_MIN 1 -@@ -1328,6 +1341,47 @@ static const struct v4l2_ioctl_ops camera0_ioctl_ops = { - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - }; - -+static const struct v4l2_ioctl_ops camera0_ioctl_ops_gstreamer = { -+ /* overlay */ -+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, -+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, -+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, -+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, -+ .vidioc_overlay = vidioc_overlay, -+ .vidioc_g_fbuf = vidioc_g_fbuf, -+ -+ /* inputs */ -+ .vidioc_enum_input = vidioc_enum_input, -+ .vidioc_g_input = vidioc_g_input, -+ .vidioc_s_input = vidioc_s_input, -+ -+ /* capture */ -+ .vidioc_querycap = vidioc_querycap, -+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, -+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, -+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, -+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, -+ -+ /* buffer management */ -+ .vidioc_reqbufs = vb2_ioctl_reqbufs, -+ .vidioc_create_bufs = vb2_ioctl_create_bufs, -+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, -+ .vidioc_querybuf = vb2_ioctl_querybuf, -+ .vidioc_qbuf = vb2_ioctl_qbuf, -+ .vidioc_dqbuf = vb2_ioctl_dqbuf, -+ /* Remove this function ptr to fix gstreamer bug -+ .vidioc_enum_framesizes = vidioc_enum_framesizes, */ -+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals, -+ .vidioc_g_parm = vidioc_g_parm, -+ .vidioc_s_parm = vidioc_s_parm, -+ .vidioc_streamon = vb2_ioctl_streamon, -+ .vidioc_streamoff = vb2_ioctl_streamoff, -+ -+ .vidioc_log_status = v4l2_ctrl_log_status, -+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -+}; -+ - /* ------------------------------------------------------------------ - Driver init/finalise - ------------------------------------------------------------------*/ -@@ -1574,6 +1628,11 @@ static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev, - int ret; - - *vfd = vdev_template; -+ if (gst_v4l2src_is_broken) { -+ v4l2_info(&dev->v4l2_dev, -+ "Work-around for gstreamer issue is active.\n"); -+ vfd->ioctl_ops = &camera0_ioctl_ops_gstreamer; -+ } - - vfd->v4l2_dev = &dev->v4l2_dev; - --- -1.9.3 - - -From fd0bbac9669c337a4a5a67e1016c1ee4f58db786 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 28 May 2014 21:01:03 +0100 -Subject: [PATCH 123/124] fiq_fsm: Enable by default - ---- - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index f2195d2..dc7cd32 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -243,7 +243,7 @@ static struct dwc_otg_driver_module_params dwc_otg_module_params = { - //Global variable to switch the fiq fix on or off - bool fiq_enable = 1; - // Global variable to enable the split transaction fix --bool fiq_fsm_enable = false; -+bool fiq_fsm_enable = true; - //Bulk split-transaction NAK holdoff in microframes - uint16_t nak_holdoff = 8; - --- -1.9.3 - - -From d473d7cc074b775f5e3ff20d09a3f8d37aa97920 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 3 Jun 2014 18:40:45 +0100 -Subject: [PATCH 124/124] config: Add CONFIG_HID_XINMO - ---- - arch/arm/configs/bcmrpi_defconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 75aa56d..bb9f0ac 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -797,6 +797,7 @@ CONFIG_HID_THINGM=m - CONFIG_HID_THRUSTMASTER=m - CONFIG_HID_WACOM=m - CONFIG_HID_WIIMOTE=m -+CONFIG_HID_XINMO=m - CONFIG_HID_ZEROPLUS=m - CONFIG_HID_ZYDACRON=m - CONFIG_HID_PID=y + print_debug + ("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d success=%d\n", +- (void *)fb->fb.screen_base, (void *)fb->fb.fix.smem_start, ++ (void *)fb->fb.screen_base, (void *)fb->fb_bus_address, + fbinfo->xres, fbinfo->yres, fbinfo->bpp, + fbinfo->pitch, (int)fb->fb.screen_size, val); + +@@ -457,11 +460,11 @@ static void bcm2708_fb_copyarea(struct fb_info *info, + + for (y = 0; y < region->height; y += scanlines_per_cb) { + dma_addr_t src = +- fb->fb.fix.smem_start + ++ fb->fb_bus_address + + bytes_per_pixel * region->sx + + (region->sy + y) * fb->fb.fix.line_length; + dma_addr_t dst = +- fb->fb.fix.smem_start + ++ fb->fb_bus_address + + bytes_per_pixel * region->dx + + (region->dy + y) * fb->fb.fix.line_length; + +@@ -499,10 +502,10 @@ static void bcm2708_fb_copyarea(struct fb_info *info, + stride = -fb->fb.fix.line_length; + } + set_dma_cb(cb, burst_size, +- fb->fb.fix.smem_start + dy * fb->fb.fix.line_length + ++ fb->fb_bus_address + dy * fb->fb.fix.line_length + + bytes_per_pixel * region->dx, + stride, +- fb->fb.fix.smem_start + sy * fb->fb.fix.line_length + ++ fb->fb_bus_address + sy * fb->fb.fix.line_length + + bytes_per_pixel * region->sx, + stride, + region->width * bytes_per_pixel, -- 1.9.3