diff --git a/projects/RPi/linux/linux.arm.conf b/projects/RPi/linux/linux.arm.conf index f0aae3c01b..754655c337 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.15.7 Kernel Configuration +# Linux/arm 3.16.0 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -9,8 +9,7 @@ CONFIG_STACKTRACE_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y CONFIG_TRACE_IRQFLAGS_SUPPORT=y -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_NEED_DMA_MAP_STATE=y @@ -51,6 +50,7 @@ CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_CROSS_MEMORY_ATTACH=y CONFIG_FHANDLE=y # CONFIG_USELIB is not set # CONFIG_AUDIT is not set @@ -133,14 +133,13 @@ CONFIG_RD_GZIP=y # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set -CONFIG_INITRAMFS_COMPRESSION_NONE=y -# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_ANON_INODES=y CONFIG_HAVE_UID16=y CONFIG_EXPERT=y # CONFIG_UID16 is not set +# CONFIG_SGETMASK_SYSCALL is not set # CONFIG_SYSFS_SYSCALL is not set CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y @@ -305,7 +304,6 @@ CONFIG_ARCH_BCM2708=y # CONFIG_ARCH_S5P64X0 is not set # CONFIG_ARCH_S5PC100 is not set # CONFIG_ARCH_S5PV210 is not set -# CONFIG_ARCH_EXYNOS is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP1 is not set # CONFIG_PLAT_SPEAR is not set @@ -347,7 +345,6 @@ CONFIG_KUSER_HELPERS=y # CONFIG_CACHE_L2X0 is not set CONFIG_ARM_L1_CACHE_SHIFT=5 CONFIG_ARM_DMA_MEM_BUFFERABLE=y -CONFIG_ARM_NR_BANKS=8 CONFIG_ARM_ERRATA_326103=y CONFIG_ARM_ERRATA_411920=y CONFIG_ARM_ERRATA_364296=y @@ -401,7 +398,6 @@ CONFIG_MIGRATION=y CONFIG_ZONE_DMA_FLAG=0 # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -CONFIG_CROSS_MEMORY_ATTACH=y CONFIG_NEED_PER_CPU_KM=y CONFIG_CLEANCACHE=y CONFIG_FRONTSWAP=y @@ -497,10 +493,12 @@ CONFIG_BINFMT_SCRIPT=y # Power management options # # CONFIG_SUSPEND is not set +# CONFIG_HIBERNATION is not set # CONFIG_PM_RUNTIME is not set CONFIG_CPU_PM=y CONFIG_ARCH_SUSPEND_POSSIBLE=y # CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_NET=y # @@ -833,7 +831,7 @@ CONFIG_HAVE_BPF_JIT=y # # Generic Driver Options # -CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_STANDALONE=y @@ -867,11 +865,11 @@ CONFIG_CMA_AREAS=7 # # Bus devices # -# CONFIG_ARM_CCI is not set +# CONFIG_BRCMSTB_GISB_ARB is not set # CONFIG_CONNECTOR is not set # CONFIG_MTD is not set -# CONFIG_PARPORT is not set CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_NULL_BLK is not set # CONFIG_BLK_DEV_COW_COMMON is not set @@ -894,10 +892,8 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # # CONFIG_SENSORS_LIS3LV02D is not set # CONFIG_AD525X_DPOT is not set -# CONFIG_ATMEL_PWM is not set # CONFIG_DUMMY_IRQ is not set # CONFIG_ICS932S401 is not set -# CONFIG_ATMEL_SSC is not set # CONFIG_ENCLOSURE_SERVICES is not set # CONFIG_APDS9802ALS is not set # CONFIG_ISL29003 is not set @@ -1129,11 +1125,17 @@ CONFIG_AR5523=m CONFIG_WCN36XX=m # CONFIG_WCN36XX_DEBUGFS is not set CONFIG_B43=m +CONFIG_B43_BCMA=y CONFIG_B43_SSB=y +CONFIG_B43_BUSES_BCMA_AND_SSB=y +# CONFIG_B43_BUSES_BCMA is not set +# CONFIG_B43_BUSES_SSB is not set # CONFIG_B43_SDIO is not set +CONFIG_B43_BCMA_PIO=y CONFIG_B43_PIO=y CONFIG_B43_PHY_N=y CONFIG_B43_PHY_LP=y +CONFIG_B43_PHY_HT=y CONFIG_B43_LEDS=y CONFIG_B43_HWRNG=y # CONFIG_B43_DEBUG is not set @@ -1241,6 +1243,7 @@ CONFIG_INPUT_MISC=y # CONFIG_INPUT_MMA8450 is not set # CONFIG_INPUT_MPU3050 is not set # CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set # CONFIG_INPUT_GPIO_TILT_POLLED is not set # CONFIG_INPUT_ATI_REMOTE2 is not set # CONFIG_INPUT_KEYSPAN_REMOTE is not set @@ -1281,6 +1284,7 @@ CONFIG_UNIX98_PTYS=y # # Serial drivers # +CONFIG_SERIAL_EARLYCON=y # CONFIG_SERIAL_8250 is not set # @@ -1289,11 +1293,13 @@ CONFIG_UNIX98_PTYS=y # CONFIG_SERIAL_AMBA_PL010 is not set CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set # CONFIG_SERIAL_MAX3100 is not set # CONFIG_SERIAL_MAX310X is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set # CONFIG_SERIAL_ALTERA_JTAGUART is not set # CONFIG_SERIAL_ALTERA_UART is not set # CONFIG_SERIAL_IFX6X60 is not set @@ -1305,14 +1311,13 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_IPMI_HANDLER is not set 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=m # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set CONFIG_BRCM_CHAR_DRIVERS=y CONFIG_BCM_VC_CMA=y +# CONFIG_BCM_VC_SM is not set CONFIG_I2C=y CONFIG_I2C_BOARDINFO=y # CONFIG_I2C_COMPAT is not set @@ -1375,6 +1380,7 @@ CONFIG_SPI_MASTER=y # CONFIG_SPI_BCM2835 is not set CONFIG_SPI_BCM2708=y # CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_CADENCE is not set # CONFIG_SPI_GPIO is not set # CONFIG_SPI_OC_TINY is not set # CONFIG_SPI_PL022 is not set @@ -1421,7 +1427,6 @@ CONFIG_GPIO_SYSFS=y # # CONFIG_GPIO_GENERIC_PLATFORM is not set # CONFIG_GPIO_PL061 is not set -# CONFIG_GPIO_RCAR is not set # CONFIG_GPIO_SCH311X is not set # @@ -1557,11 +1562,13 @@ CONFIG_HWMON=y # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 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_SHTC1 is not set # CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_EMC1403 is not set # CONFIG_SENSORS_EMC2103 is not set @@ -1624,7 +1631,12 @@ CONFIG_BCMA_POSSIBLE=y # # Broadcom specific AMBA # -# CONFIG_BCMA is not set +CONFIG_BCMA=m +CONFIG_BCMA_BLOCKIO=y +# CONFIG_BCMA_HOST_SOC is not set +CONFIG_BCMA_DRIVER_GMAC_CMN=y +# CONFIG_BCMA_DRIVER_GPIO is not set +# CONFIG_BCMA_DEBUG is not set # # Multifunction device drivers @@ -1634,6 +1646,7 @@ CONFIG_MFD_CORE=m # CONFIG_PMIC_ADP5520 is not set # CONFIG_MFD_AAT2870_CORE is not set # CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_AXP20X is not set # CONFIG_MFD_CROS_EC is not set # CONFIG_MFD_ASIC3 is not set # CONFIG_PMIC_DA903X is not set @@ -1669,7 +1682,6 @@ CONFIG_MFD_RTSX_USB=m # CONFIG_MFD_SM501 is not set # CONFIG_MFD_SMSC is not set # CONFIG_ABX500_CORE is not set -# CONFIG_MFD_STMPE is not set # CONFIG_MFD_SYSCON is not set # CONFIG_MFD_TI_AM335X_TSCADC is not set # CONFIG_MFD_LP3943 is not set @@ -1703,7 +1715,6 @@ CONFIG_MFD_RTSX_USB=m # CONFIG_MFD_WM831X_SPI is not set # CONFIG_MFD_WM8350_I2C is not set # CONFIG_MFD_WM8994 is not set -# CONFIG_VEXPRESS_CONFIG is not set # CONFIG_REGULATOR is not set CONFIG_MEDIA_SUPPORT=m @@ -1960,6 +1971,7 @@ CONFIG_MEDIA_TUNER_E4000=m CONFIG_MEDIA_TUNER_FC2580=m CONFIG_MEDIA_TUNER_M88TS2022=m CONFIG_MEDIA_TUNER_TUA9001=m +CONFIG_MEDIA_TUNER_SI2157=m CONFIG_MEDIA_TUNER_IT913X=m CONFIG_MEDIA_TUNER_R820T=m @@ -2019,6 +2031,7 @@ CONFIG_DVB_EC100=m CONFIG_DVB_CXD2820R=m CONFIG_DVB_RTL2830=m CONFIG_DVB_RTL2832=m +CONFIG_DVB_SI2168=m # # DVB-C (cable) frontends @@ -2111,16 +2124,13 @@ 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 # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_BROADSHEET is not set # CONFIG_FB_AUO_K190X is not set # CONFIG_FB_SIMPLE is not set -# CONFIG_EXYNOS_VIDEO is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # CONFIG_VGASTATE is not set @@ -2174,6 +2184,7 @@ CONFIG_SND_USB_CAIAQ=m CONFIG_SND_USB_CAIAQ_INPUT=y CONFIG_SND_USB_6FIRE=m CONFIG_SND_USB_HIFACE=m +CONFIG_SND_BCD2000=m CONFIG_SND_SOC=m CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y # CONFIG_SND_ATMEL_SOC is not set @@ -2183,6 +2194,19 @@ 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 + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set CONFIG_SND_SOC_I2C_AND_SPI=m # @@ -2193,7 +2217,9 @@ CONFIG_SND_SOC_I2C_AND_SPI=m # CONFIG_SND_SOC_AK4554 is not set # CONFIG_SND_SOC_AK4642 is not set # CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set # CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set # CONFIG_SND_SOC_CS42L73 is not set # CONFIG_SND_SOC_CS4270 is not set # CONFIG_SND_SOC_CS4271 is not set @@ -2202,13 +2228,14 @@ CONFIG_SND_SOC_I2C_AND_SPI=m # CONFIG_SND_SOC_PCM1681 is not set # CONFIG_SND_SOC_PCM1792A is not set CONFIG_SND_SOC_PCM512x=m -# CONFIG_SND_SOC_PCM512x_I2C is not set +CONFIG_SND_SOC_PCM512x_I2C=m # CONFIG_SND_SOC_PCM512x_SPI is not set CONFIG_SND_SOC_PCM1794A=m CONFIG_SND_SOC_PCM5102A=m # CONFIG_SND_SOC_SGTL5000 is not set # CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set # CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_STA350 is not set # CONFIG_SND_SOC_TAS5086 is not set # CONFIG_SND_SOC_TLV320AIC3X is not set # CONFIG_SND_SOC_WM8510 is not set @@ -2297,6 +2324,7 @@ CONFIG_SONY_FF=y # CONFIG_HID_STEELSERIES is not set CONFIG_HID_SPINELPLUS=y CONFIG_HID_SUNPLUS=y +CONFIG_HID_RMI=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TIVO=y @@ -2326,7 +2354,6 @@ CONFIG_USB_SUPPORT=y CONFIG_USB_COMMON=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB=y -# CONFIG_USB_DEBUG is not set CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # @@ -2336,6 +2363,7 @@ CONFIG_USB_DEFAULT_PERSIST=y # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_OTG_WHITELIST is not set # CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set CONFIG_USB_MON=m # CONFIG_USB_WUSB_CBAF is not set @@ -2351,10 +2379,12 @@ CONFIG_USB_MON=m # CONFIG_USB_ISP1362_HCD is not set # CONFIG_USB_FUSBH200_HCD is not set # CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set # CONFIG_USB_OHCI_HCD is not set # CONFIG_USB_SL811_HCD is not set # CONFIG_USB_R8A66597_HCD is not set CONFIG_USB_DWCOTG=y +# CONFIG_USB_HCD_BCMA is not set # CONFIG_USB_HCD_SSB is not set # CONFIG_USB_HCD_TEST_MODE is not set @@ -2485,14 +2515,12 @@ CONFIG_USB_SERIAL_PL2303=m # USB Physical Layer drivers # # CONFIG_USB_PHY is not set -# CONFIG_USB_OTG_FSM is not set # CONFIG_NOP_USB_XCEIV is not set # CONFIG_AM335X_PHY_USB is not set # CONFIG_SAMSUNG_USB2PHY is not set # CONFIG_SAMSUNG_USB3PHY is not set # CONFIG_USB_GPIO_VBUS is not set # CONFIG_USB_ISP1301 is not set -# CONFIG_USB_RCAR_PHY is not set # CONFIG_USB_ULPI is not set # CONFIG_USB_GADGET is not set CONFIG_MMC=y @@ -2523,6 +2551,8 @@ CONFIG_MMC_SDHCI_BCM2708_DMA=y # CONFIG_MMC_DW is not set # CONFIG_MMC_VUB300 is not set # CONFIG_MMC_USHC is not set +# CONFIG_MMC_USDHI6ROL0 is not set +CONFIG_MMC_REALTEK_USB=m # CONFIG_MEMSTICK is not set CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -2541,12 +2571,15 @@ CONFIG_LEDS_GPIO=y # CONFIG_LEDS_LP8501 is not set # CONFIG_LEDS_PCA955X is not set # CONFIG_LEDS_PCA963X is not set -# CONFIG_LEDS_PCA9685 is not set # CONFIG_LEDS_DAC124S085 is not set # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_LT3593 is not set # CONFIG_LEDS_TCA6507 is not set # CONFIG_LEDS_LM355x is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# # CONFIG_LEDS_BLINKM is not set # @@ -2616,6 +2649,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_DS1343 is not set # CONFIG_RTC_DRV_DS1347 is not set # CONFIG_RTC_DRV_DS1390 is not set # CONFIG_RTC_DRV_MAX6902 is not set @@ -2624,6 +2658,7 @@ CONFIG_RTC_DRV_DS1307=m # CONFIG_RTC_DRV_DS3234 is not set # CONFIG_RTC_DRV_PCF2123 is not set # CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_MCP795 is not set # # Platform RTC drivers @@ -2649,6 +2684,7 @@ CONFIG_RTC_DRV_DS1307=m # CONFIG_RTC_DRV_PL030 is not set # CONFIG_RTC_DRV_PL031 is not set # CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_XGENE is not set # # HID Sensor RTC drivers @@ -2693,8 +2729,6 @@ CONFIG_W35UND=m # CONFIG_RTLLIB is not set CONFIG_R8712U=m # CONFIG_R8188EU is not set -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 @@ -2739,6 +2773,10 @@ CONFIG_LIRC_XBOX=m # CONFIG_LUSTRE_FS is not set # CONFIG_DGAP is not set # CONFIG_GS_FPGABOOT is not set + +# +# SOC (System On Chip) specific Drivers +# CONFIG_CLKDEV_LOOKUP=y CONFIG_HAVE_CLK_PREPARE=y CONFIG_COMMON_CLK=y @@ -2755,6 +2793,7 @@ CONFIG_COMMON_CLK=y # CONFIG_SH_TIMER_MTU2 is not set # CONFIG_SH_TIMER_TMU is not set # CONFIG_EM_TIMER_STI is not set +# CONFIG_CLKSRC_VERSATILE is not set # CONFIG_MAILBOX is not set # CONFIG_IOMMU_SUPPORT is not set @@ -2779,6 +2818,7 @@ CONFIG_COMMON_CLK=y # PHY Subsystem # # CONFIG_GENERIC_PHY is not set +# CONFIG_BCM_KONA_USB2_PHY is not set # CONFIG_PHY_SAMSUNG_USB2 is not set # CONFIG_POWERCAP is not set # CONFIG_MCB is not set @@ -3075,6 +3115,7 @@ CONFIG_PANIC_TIMEOUT=0 # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PI_LIST is not set # CONFIG_DEBUG_SG is not set # CONFIG_DEBUG_NOTIFIERS is not set # CONFIG_DEBUG_CREDENTIALS is not set @@ -3118,6 +3159,7 @@ CONFIG_TRACING_SUPPORT=y # CONFIG_DMA_API_DEBUG is not set # CONFIG_TEST_MODULE is not set # CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set diff --git a/projects/RPi/options b/projects/RPi/options index c5cdf5320f..4effdcc999 100644 --- a/projects/RPi/options +++ b/projects/RPi/options @@ -106,7 +106,7 @@ # Kernel to use. values can be: # default: default mainline kernel - LINUX="3.15" + 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 d72702dcd4..2957f02515 100644 --- a/projects/RPi/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi/patches/linux/linux-01-RPi_support.patch @@ -1,28 +1,28 @@ -From a5ba2809a7860cfd19ad373ad024713a5ebb7b38 Mon Sep 17 00:00:00 2001 +From 6bc5831c3e7b2b70c22ac80371697fc0d7a37f3e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 01/81] Main bcm2708 linux port +Subject: [PATCH 01/69] Main bcm2708 linux port Signed-off-by: popcornmix --- arch/arm/Kconfig | 17 + arch/arm/Kconfig.debug | 8 + arch/arm/Makefile | 1 + - arch/arm/configs/bcmrpi_cutdown_defconfig | 474 +++++++ + arch/arm/configs/bcmrpi_cutdown_defconfig | 474 ++++++++ arch/arm/configs/bcmrpi_defconfig | 510 ++++++++ - arch/arm/configs/bcmrpi_emergency_defconfig | 532 ++++++++ + arch/arm/configs/bcmrpi_emergency_defconfig | 532 +++++++++ arch/arm/kernel/process.c | 10 + arch/arm/mach-bcm2708/Kconfig | 34 + arch/arm/mach-bcm2708/Makefile | 7 + 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 | 720 +++++++++++ + arch/arm/mach-bcm2708/bcm2708.c | 721 +++++++++++ arch/arm/mach-bcm2708/bcm2708.h | 49 + arch/arm/mach-bcm2708/bcm2708_gpio.c | 361 ++++++ arch/arm/mach-bcm2708/clock.c | 61 + arch/arm/mach-bcm2708/clock.h | 24 + - arch/arm/mach-bcm2708/dma.c | 399 ++++++ + arch/arm/mach-bcm2708/dma.c | 399 +++++++ arch/arm/mach-bcm2708/include/mach/arm_control.h | 419 +++++++ arch/arm/mach-bcm2708/include/mach/arm_power.h | 60 + arch/arm/mach-bcm2708/include/mach/clkdev.h | 7 + @@ -45,18 +45,21 @@ Signed-off-by: popcornmix arch/arm/mach-bcm2708/include/mach/vmalloc.h | 20 + arch/arm/mach-bcm2708/power.c | 194 +++ arch/arm/mach-bcm2708/vc_mem.c | 432 +++++++ - arch/arm/mach-bcm2708/vcio.c | 474 +++++++ + arch/arm/mach-bcm2708/vcio.c | 474 ++++++++ arch/arm/mm/Kconfig | 2 +- arch/arm/mm/proc-v6.S | 15 +- arch/arm/tools/mach-types | 1 + + drivers/mmc/card/block.c | 2 +- + drivers/mmc/core/sd.c | 110 +- drivers/mmc/host/Kconfig | 21 + drivers/mmc/host/Makefile | 1 + - drivers/mmc/host/sdhci-bcm2708.c | 1424 ++++++++++++++++++++++ - drivers/mmc/host/sdhci.c | 203 ++- - drivers/mmc/host/sdhci.h | 37 + + drivers/mmc/host/sdhci-bcm2708.c | 1394 ++++++++++++++++++++++ + drivers/mmc/host/sdhci.c | 170 ++- + drivers/mmc/host/sdhci.h | 34 + drivers/tty/serial/amba-pl011.c | 2 +- - include/linux/mmc/sdhci.h | 2 + - 51 files changed, 7792 insertions(+), 72 deletions(-) + include/linux/mmc/host.h | 1 + + include/linux/mmc/sdhci.h | 1 + + 54 files changed, 7834 insertions(+), 77 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 +100,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 34c7a24..ed579ab 100644 +index 290f02ee..bf32dc1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -385,6 +385,22 @@ config ARCH_AT91 +@@ -374,6 +374,22 @@ config ARCH_AT91 This enables support for systems based on Atmel AT91RM9200 and AT91SAM9* processors. @@ -123,7 +126,7 @@ index 34c7a24..ed579ab 100644 config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" select ARCH_REQUIRE_GPIOLIB -@@ -1069,6 +1085,7 @@ source "arch/arm/plat-versatile/Kconfig" +@@ -1034,6 +1050,7 @@ source "arch/arm/plat-versatile/Kconfig" source "arch/arm/mach-vt8500/Kconfig" source "arch/arm/mach-w90x900/Kconfig" @@ -132,10 +135,10 @@ index 34c7a24..ed579ab 100644 source "arch/arm/mach-zynq/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index eab8ecb..34f5efb 100644 +index 8f905950..2a4438d 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug -@@ -916,6 +916,14 @@ choice +@@ -937,6 +937,14 @@ choice options; the platform specific options are deprecated and will be soon removed. @@ -151,12 +154,12 @@ index eab8ecb..34f5efb 100644 config DEBUG_EXYNOS_UART diff --git a/arch/arm/Makefile b/arch/arm/Makefile -index 41c1931..092cd25 100644 +index 6721fab..08df04d 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile -@@ -143,6 +143,7 @@ textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 - # by CONFIG_* macro name. +@@ -145,6 +145,7 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000 machine-$(CONFIG_ARCH_AT91) += at91 + machine-$(CONFIG_ARCH_AXXIA) += axxia machine-$(CONFIG_ARCH_BCM) += bcm +machine-$(CONFIG_ARCH_BCM2708) += bcm2708 machine-$(CONFIG_ARCH_BERLIN) += berlin @@ -1781,7 +1784,7 @@ index 0000000..67039c3 +initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-bcm2708/armctrl.c b/arch/arm/mach-bcm2708/armctrl.c new file mode 100644 -index 0000000..da18725 +index 0000000..efade23 --- /dev/null +++ b/arch/arm/mach-bcm2708/armctrl.c @@ -0,0 +1,208 @@ @@ -1961,7 +1964,7 @@ index 0000000..da18725 + +static struct irq_chip armctrl_chip = { + .name = "ARMCTRL", -+ .irq_ack = armctrl_mask_irq, ++ .irq_ack = NULL, + .irq_mask = armctrl_mask_irq, + .irq_unmask = armctrl_unmask_irq, + .irq_set_wake = armctrl_set_wake, @@ -2028,10 +2031,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..752ae6e +index 0000000..632023a --- /dev/null +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -0,0 +1,720 @@ +@@ -0,0 +1,721 @@ +/* + * linux/arch/arm/mach-bcm2708/bcm2708.c + * @@ -2190,7 +2193,7 @@ index 0000000..752ae6e + return timer_read(); +} + -+static u32 notrace bcm2708_read_sched_clock(void) ++static u64 notrace bcm2708_read_sched_clock(void) +{ + return timer_read(); +} @@ -2610,7 +2613,8 @@ index 0000000..752ae6e + 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) ++ } while ((signed long) cycles >= 0 && ++ (signed long) (readl(__io_address(ST_BASE + 0x04)) - stc) + >= (signed long) cycles); + return 0; +} @@ -2666,7 +2670,7 @@ index 0000000..752ae6e + */ + setup_irq(IRQ_TIMER3, &bcm2708_timer_irq); + -+ setup_sched_clock(bcm2708_read_sched_clock, 32, STC_FREQ_HZ); ++ sched_clock_register(bcm2708_read_sched_clock, 32, STC_FREQ_HZ); + + timer0_clockevent.mult = + div_sc(STC_FREQ_HZ, NSEC_PER_SEC, timer0_clockevent.shift); @@ -6526,7 +6530,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 5bf7c3c..02c089e 100644 +index c348eae..4f31fbf 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -358,7 +358,7 @@ config CPU_PJ4B @@ -6577,11 +6581,182 @@ index a10297d..c9ddd87 100644 ag5evm MACH_AG5EVM AG5EVM 3189 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/card/block.c b/drivers/mmc/card/block.c +index 452782b..eee5aef 100644 +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -1404,7 +1404,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, + brq->data.blocks = 1; + } + +- if (brq->data.blocks > 1 || do_rel_wr) { ++ if (brq->data.blocks > 1 || do_rel_wr || card->host->caps2 & MMC_CAP2_FORCE_MULTIBLOCK) { + /* SPI multiblock writes terminate using a special + * token, not a STOP_TRANSMISSION request. + */ +diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c +index 0c44510..eb511d6 100644 +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -15,6 +15,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -67,6 +69,15 @@ static const unsigned int sd_au_size[] = { + __res & __mask; \ + }) + ++// timeout for tries ++static const unsigned long retry_timeout_ms= 10*1000; ++ ++// try at least 10 times, even if timeout is reached ++static const int retry_min_tries= 10; ++ ++// delay between tries ++static const unsigned long retry_delay_ms= 10; ++ + /* + * Given the decoded CSD structure, decode the raw CID to our CID structure. + */ +@@ -219,12 +230,63 @@ static int mmc_decode_scr(struct mmc_card *card) + } + + /* +- * Fetch and process SD Status register. ++ * Fetch and process SD Configuration Register. ++ */ ++static int mmc_read_scr(struct mmc_card *card) ++{ ++ unsigned long timeout_at; ++ int err, tries; ++ ++ timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms ); ++ tries= 0; ++ ++ while( tries < retry_min_tries || time_before( jiffies, timeout_at ) ) ++ { ++ unsigned long delay_at; ++ tries++; ++ ++ err = mmc_app_send_scr(card, card->raw_scr); ++ if( !err ) ++ break; // success!!! ++ ++ touch_nmi_watchdog(); // we are still alive! ++ ++ // delay ++ delay_at= jiffies + msecs_to_jiffies( retry_delay_ms ); ++ while( time_before( jiffies, delay_at ) ) ++ { ++ mdelay( 1 ); ++ touch_nmi_watchdog(); // we are still alive! ++ } ++ } ++ ++ if( err) ++ { ++ pr_err("%s: failed to read SD Configuration register (SCR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err ); ++ return err; ++ } ++ ++ if( tries > 1 ) ++ { ++ pr_info("%s: could read SD Configuration register (SCR) at the %dth attempt\n", mmc_hostname(card->host), tries ); ++ } ++ ++ err = mmc_decode_scr(card); ++ if (err) ++ return err; ++ ++ return err; ++} ++ ++/* ++ * Fetch and process SD Status Register. + */ + static int mmc_read_ssr(struct mmc_card *card) + { ++ unsigned long timeout_at; + unsigned int au, es, et, eo; + int err, i; ++ int tries; + u32 *ssr; + + if (!(card->csd.cmdclass & CCC_APP_SPEC)) { +@@ -237,14 +299,40 @@ static int mmc_read_ssr(struct mmc_card *card) + if (!ssr) + return -ENOMEM; + +- err = mmc_app_sd_status(card, ssr); +- if (err) { +- pr_warning("%s: problem reading SD Status " +- "register.\n", mmc_hostname(card->host)); +- err = 0; ++ timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms ); ++ tries= 0; ++ ++ while( tries < retry_min_tries || time_before( jiffies, timeout_at ) ) ++ { ++ unsigned long delay_at; ++ tries++; ++ ++ err= mmc_app_sd_status(card, ssr); ++ if( !err ) ++ break; // sucess!!! ++ ++ touch_nmi_watchdog(); // we are still alive! ++ ++ // delay ++ delay_at= jiffies + msecs_to_jiffies( retry_delay_ms ); ++ while( time_before( jiffies, delay_at ) ) ++ { ++ mdelay( 1 ); ++ touch_nmi_watchdog(); // we are still alive! ++ } ++ } ++ ++ if( err) ++ { ++ pr_err("%s: failed to read SD Status register (SSR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err ); + goto out; + } + ++ if( tries > 1 ) ++ { ++ pr_info("%s: read SD Status register (SSR) after %d attempts\n", mmc_hostname(card->host), tries ); ++ } ++ + for (i = 0; i < 16; i++) + ssr[i] = be32_to_cpu(ssr[i]); + +@@ -818,14 +906,10 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, + + if (!reinit) { + /* +- * Fetch SCR from card. ++ * Fetch and decode SD Configuration register. + */ +- err = mmc_app_send_scr(card, card->raw_scr); +- if (err) +- return err; +- +- err = mmc_decode_scr(card); +- if (err) ++ err = mmc_read_scr(card); ++ if( err ) + return err; + + /* diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 8aaf8c1..f1cd961 100644 +index a565254..b152bb3 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig -@@ -272,6 +272,27 @@ config MMC_SDHCI_BCM_KONA +@@ -270,6 +270,27 @@ config MMC_SDHCI_BCM_KONA If you have a controller with this interface, say Y or M here. @@ -6610,7 +6785,7 @@ index 8aaf8c1..f1cd961 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 0c8aa5e..a8614dd 100644 +index 7f81ddf..635064e 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o @@ -6623,10 +6798,10 @@ index 0c8aa5e..a8614dd 100644 obj-$(CONFIG_MMC_OMAP) += omap.o diff --git a/drivers/mmc/host/sdhci-bcm2708.c b/drivers/mmc/host/sdhci-bcm2708.c new file mode 100644 -index 0000000..d8ef77c +index 0000000..6e777f4 --- /dev/null +++ b/drivers/mmc/host/sdhci-bcm2708.c -@@ -0,0 +1,1424 @@ +@@ -0,0 +1,1394 @@ +/* + * sdhci-bcm2708.c Support for SDHCI device on BCM2708 + * Copyright (c) 2010 Broadcom @@ -6680,7 +6855,6 @@ index 0000000..d8ef77c +#undef CONFIG_MMC_SDHCI_BCM2708_DMA +#define CONFIG_MMC_SDHCI_BCM2708_DMA y + -+#define USE_SYNC_AFTER_DMA +#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA +/* #define CHECK_DMA_USE */ +#endif @@ -6702,7 +6876,12 @@ index 0000000..d8ef77c +#define BCM2708_SDHCI_SLEEP_TIMEOUT 1000 /* msecs */ + +/* Mhz clock that the EMMC core is running at. Should match the platform clockman settings */ -+#define BCM2708_EMMC_CLOCK_FREQ 80000000 ++#define BCM2708_EMMC_CLOCK_FREQ 50000000 ++ ++#define REG_EXRDFIFO_EN 0x80 ++#define REG_EXRDFIFO_CFG 0x84 ++ ++int cycle_delay=2; + +/*****************************************************************************\ + * * @@ -6758,6 +6937,12 @@ index 0000000..d8ef77c + return (unsigned long)((hptime() - t) * HPTIME_CLK_NS); +} + ++static bool allow_highspeed = 1; ++static int emmc_clock_freq = BCM2708_EMMC_CLOCK_FREQ; ++static bool sync_after_dma = 1; ++static bool missing_status = 1; ++bool extra_messages = 0; ++ +#if 0 +static void hptime_test(void) +{ @@ -6870,19 +7055,19 @@ index 0000000..d8ef77c + /* host->clock is the clock freq in Hz */ + static hptime_t last_write_hpt; + hptime_t now = hptime(); -+ ns_2clk = 2000000000/host->clock; ++ ns_2clk = cycle_delay*1000000/(host->clock/1000); + + if (now == last_write_hpt || now == last_write_hpt+1) { + /* we can't guarantee any significant time has + * passed - we'll have to wait anyway ! */ -+ udelay((ns_2clk+1000-1)/1000); ++ ndelay(ns_2clk); + } else + { + /* we must have waited at least this many ns: */ + unsigned int ns_wait = HPTIME_CLK_NS * -+ (last_write_hpt - now - 1); ++ (now - last_write_hpt - 1); + if (ns_wait < ns_2clk) -+ udelay((ns_2clk-ns_wait+500)/1000); ++ ndelay(ns_2clk - ns_wait); + } + last_write_hpt = now; + } @@ -6898,13 +7083,13 @@ index 0000000..d8ef77c + ier &= ~SDHCI_INT_DATA_TIMEOUT; + writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); + timeout_disabled = true; -+ udelay((ns_2clk+1000-1)/1000); ++ ndelay(ns_2clk); + } else if (timeout_disabled) { + ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE); + ier |= SDHCI_INT_DATA_TIMEOUT; + writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); + timeout_disabled = false; -+ udelay((ns_2clk+1000-1)/1000); ++ ndelay(ns_2clk); + } +#endif + writel(val, host->ioaddr + reg); @@ -6982,68 +7167,9 @@ index 0000000..d8ef77c + +static unsigned int sdhci_bcm2708_get_max_clock(struct sdhci_host *host) +{ -+ return 20000000; // this value is in Hz (20MHz) ++ return emmc_clock_freq; +} + -+static unsigned int sdhci_bcm2708_get_timeout_clock(struct sdhci_host *host) -+{ -+ if(host->clock) -+ return (host->clock / 1000); // this value is in kHz (100MHz) -+ else -+ return (sdhci_bcm2708_get_max_clock(host) / 1000); -+} -+ -+static void sdhci_bcm2708_set_clock(struct sdhci_host *host, unsigned int clock) -+{ -+ int div = 0; -+ u16 clk = 0; -+ unsigned long timeout; -+ -+ if (clock == host->clock) -+ return; -+ -+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); -+ -+ if (clock == 0) -+ goto out; -+ -+ if (BCM2708_EMMC_CLOCK_FREQ <= clock) -+ div = 1; -+ else { -+ for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { -+ if ((BCM2708_EMMC_CLOCK_FREQ / div) <= clock) -+ break; -+ } -+ } -+ -+ DBG( "desired SD clock: %d, actual: %d\n", -+ clock, BCM2708_EMMC_CLOCK_FREQ / div); -+ -+ clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; -+ clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) -+ << SDHCI_DIVIDER_HI_SHIFT; -+ clk |= SDHCI_CLOCK_INT_EN; -+ -+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -+ -+ timeout = 20; -+ while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) -+ & SDHCI_CLOCK_INT_STABLE)) { -+ if (timeout == 0) { -+ printk(KERN_ERR "%s: Internal clock never " -+ "stabilised.\n", mmc_hostname(host->mmc)); -+ return; -+ } -+ timeout--; -+ mdelay(1); -+ } -+ -+ clk |= SDHCI_CLOCK_CARD_EN; -+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -+out: -+ host->clock = clock; -+ } -+ +/*****************************************************************************\ + * * + * DMA Operation * @@ -7324,11 +7450,11 @@ index 0000000..d8ef77c +sdhci_bcm2708_platdma_reset(struct sdhci_host *host, struct mmc_data *data) +{ + struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host); -+ unsigned long flags; ++// unsigned long flags; + + BUG_ON(NULL == host); + -+ spin_lock_irqsave(&host->lock, flags); ++// spin_lock_irqsave(&host->lock, flags); + + if (host_priv->dma_wanted) { + if (NULL == data) { @@ -7349,18 +7475,19 @@ index 0000000..d8ef77c + cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS); + + if (!(BCM2708_DMA_ACTIVE & cs)) -+ printk(KERN_INFO "%s: missed completion of " -+ "cmd %d DMA (%d/%d [%d]/[%d]) - " ++ { ++ if (extra_messages) ++ printk(KERN_INFO "%s: missed completion of " ++ "cmd DMA (%d/%d [%d]/[%d]) - " + "ignoring it\n", + mmc_hostname(host->mmc), -+ host->last_cmdop, + host_priv->sg_done, sg_todo, + host_priv->sg_ix+1, sg_len); ++ } + else -+ printk(KERN_INFO "%s: resetting ongoing cmd %d" ++ printk(KERN_INFO "%s: resetting ongoing cmd" + "DMA before %d/%d [%d]/[%d] complete\n", + mmc_hostname(host->mmc), -+ host->last_cmdop, + host_priv->sg_done, sg_todo, + host_priv->sg_ix+1, sg_len); +#ifdef CHECK_DMA_USE @@ -7408,7 +7535,7 @@ index 0000000..d8ef77c +#endif + } + -+ spin_unlock_irqrestore(&host->lock, flags); ++// spin_unlock_irqrestore(&host->lock, flags); +} + + @@ -7421,11 +7548,11 @@ index 0000000..d8ef77c + int sg_len; + int sg_ix; + int sg_todo; -+ unsigned long flags; ++// unsigned long flags; + + BUG_ON(NULL == host); + -+ spin_lock_irqsave(&host->lock, flags); ++// spin_lock_irqsave(&host->lock, flags); + data = host->data; + +#ifdef CHECK_DMA_USE @@ -7450,7 +7577,7 @@ index 0000000..d8ef77c + + if (NULL == data) { + DBG("PDMA unused completion - status 0x%X\n", dma_cs); -+ spin_unlock_irqrestore(&host->lock, flags); ++// spin_unlock_irqrestore(&host->lock, flags); + return; + } + sg = data->sg; @@ -7507,40 +7634,34 @@ index 0000000..d8ef77c + SDHCI_INT_SPACE_AVAIL); + } + } else { -+#ifdef USE_SYNC_AFTER_DMA -+ /* On the Arasan controller the stop command (which will be -+ scheduled after this completes) does not seem to work -+ properly if we allow it to be issued when we are -+ transferring data to/from the SD card. -+ We get CRC and DEND errors unless we wait for -+ the SD controller to finish reading/writing to the card. */ -+ u32 state_mask; -+ int timeout=1000000; -+ hptime_t now = hptime(); ++ if (sync_after_dma) { ++ /* On the Arasan controller the stop command (which will be ++ scheduled after this completes) does not seem to work ++ properly if we allow it to be issued when we are ++ transferring data to/from the SD card. ++ We get CRC and DEND errors unless we wait for ++ the SD controller to finish reading/writing to the card. */ ++ u32 state_mask; ++ int timeout=3*1000*1000; + -+ DBG("PDMA over - sync card\n"); -+ if (data->flags & MMC_DATA_READ) -+ state_mask = SDHCI_DOING_READ; -+ else -+ state_mask = SDHCI_DOING_WRITE; ++ DBG("PDMA over - sync card\n"); ++ if (data->flags & MMC_DATA_READ) ++ state_mask = SDHCI_DOING_READ; ++ else ++ state_mask = SDHCI_DOING_WRITE; + -+ while (0 != (sdhci_bcm2708_raw_readl(host, -+ SDHCI_PRESENT_STATE) & -+ state_mask) && --timeout > 0) -+ continue; -+ -+ if (1000000-timeout > 4000) /*ave. is about 3250*/ -+ DBG("%s: note - long %s sync %luns - " -+ "%d its.\n", -+ mmc_hostname(host->mmc), -+ data->flags & MMC_DATA_READ? "read": "write", -+ since_ns(now), 1000000-timeout); -+ if (timeout <= 0) -+ printk(KERN_ERR"%s: final %s to SD card still " -+ "running\n", -+ mmc_hostname(host->mmc), -+ data->flags & MMC_DATA_READ? "read": "write"); -+#endif ++ while (0 != (sdhci_bcm2708_raw_readl(host, SDHCI_PRESENT_STATE) ++ & state_mask) && --timeout > 0) ++ { ++ udelay(1); ++ continue; ++ } ++ if (timeout <= 0) ++ printk(KERN_ERR"%s: final %s to SD card still " ++ "running\n", ++ mmc_hostname(host->mmc), ++ data->flags & MMC_DATA_READ? "read": "write"); ++ } + if (host_priv->complete) { + (*host_priv->complete)(host); + DBG("PDMA %s complete\n", @@ -7549,7 +7670,7 @@ index 0000000..d8ef77c + SDHCI_INT_SPACE_AVAIL); + } + } -+ spin_unlock_irqrestore(&host->lock, flags); ++// spin_unlock_irqrestore(&host->lock, flags); +} + +static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id) @@ -7587,7 +7708,8 @@ index 0000000..d8ef77c + + if (!host_priv->dma_wanted) { + /* ignore this interrupt - it was reset */ -+ printk(KERN_INFO "%s: DMA IRQ %X ignored - " ++ if (extra_messages) ++ printk(KERN_INFO "%s: DMA IRQ %X ignored - " + "results were reset\n", + mmc_hostname(host->mmc), dma_cs); +#ifdef CHECK_DMA_USE @@ -7604,7 +7726,6 @@ index 0000000..d8ef77c + + result = IRQ_HANDLED; + } -+ + spin_unlock_irqrestore(&host->lock, flags); + + return result; @@ -7648,10 +7769,12 @@ index 0000000..d8ef77c + int on = simple_strtol(buf, NULL, 0); + if (on) { + host->flags |= SDHCI_USE_PLATDMA; ++ sdhci_bcm2708_writel(host, 1, REG_EXRDFIFO_EN); + printk(KERN_INFO "%s: DMA enabled\n", + mmc_hostname(host->mmc)); + } else { + host->flags &= ~(SDHCI_USE_PLATDMA | SDHCI_REQ_USE_DMA); ++ sdhci_bcm2708_writel(host, 0, REG_EXRDFIFO_EN); + printk(KERN_INFO "%s: DMA disabled\n", + mmc_hostname(host->mmc)); + } @@ -7755,7 +7878,7 @@ index 0000000..d8ef77c + int ret = 0; + + if (host->mmc) { -+ ret = mmc_suspend_host(host->mmc); ++ //ret = mmc_suspend_host(host->mmc); + } + + return ret; @@ -7768,7 +7891,7 @@ index 0000000..d8ef77c + int ret = 0; + + if (host->mmc) { -+ ret = mmc_resume_host(host->mmc); ++ //ret = mmc_resume_host(host->mmc); + } + + return ret; @@ -7787,19 +7910,9 @@ index 0000000..d8ef77c + return 1; +} + -+static unsigned int sdhci_bcm2708_quirk_spurious_crc(struct sdhci_host *host) ++static unsigned int sdhci_bcm2708_missing_status(struct sdhci_host *host) +{ -+ return 1; -+} -+ -+static unsigned int sdhci_bcm2708_quirk_voltage_broken(struct sdhci_host *host) -+{ -+ return 1; -+} -+ -+static unsigned int sdhci_bcm2708_uhs_broken(struct sdhci_host *host) -+{ -+ return 1; ++ return 1; +} + +/***************************************************************************** \ @@ -7819,11 +7932,7 @@ index 0000000..d8ef77c +#else +#error The BCM2708 SDHCI driver needs CONFIG_MMC_SDHCI_IO_ACCESSORS to be set +#endif -+ //.enable_dma = NULL, -+ .set_clock = sdhci_bcm2708_set_clock, + .get_max_clock = sdhci_bcm2708_get_max_clock, -+ //.get_min_clock = NULL, -+ .get_timeout_clock = sdhci_bcm2708_get_timeout_clock, + +#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA + // Platform DMA operations @@ -7832,9 +7941,11 @@ index 0000000..d8ef77c + .pdma_reset = sdhci_bcm2708_platdma_reset, +#endif + .extra_ints = sdhci_bcm2708_quirk_extra_ints, -+ .spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc, -+ .voltage_broken = sdhci_bcm2708_quirk_voltage_broken, -+ .uhs_broken = sdhci_bcm2708_uhs_broken, ++ ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +/*****************************************************************************\ @@ -7873,6 +7984,9 @@ index 0000000..d8ef77c + ret = PTR_ERR(host); + goto err; + } ++ if (missing_status) { ++ sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status; ++ } + + host->hw_name = "BCM2708_Arasan"; + host->ops = &sdhci_bcm2708_ops; @@ -7881,7 +7995,11 @@ index 0000000..d8ef77c + host->quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | -+ SDHCI_QUIRK_NONSTANDARD_CLOCK; ++ SDHCI_QUIRK_MISSING_CAPS | ++ SDHCI_QUIRK_NO_HISPD_BIT | ++ (sync_after_dma ? 0:SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12); ++ ++ +#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA + host->flags = SDHCI_USE_PLATDMA; +#endif @@ -7944,7 +8062,13 @@ index 0000000..d8ef77c + host_priv->dma_chan, host_priv->dma_chan_base, + host_priv->dma_irq); + -+ host->mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; ++ // we support 3.3V ++ host->caps |= SDHCI_CAN_VDD_330; ++ if (allow_highspeed) ++ host->mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; ++ ++ /* single block writes cause data loss with some SD cards! */ ++ host->mmc->caps2 |= MMC_CAP2_FORCE_MULTIBLOCK; +#endif + + ret = sdhci_add_host(host); @@ -7956,6 +8080,12 @@ index 0000000..d8ef77c + ret = device_create_file(&pdev->dev, &dev_attr_dma_wait); + ret = device_create_file(&pdev->dev, &dev_attr_status); + ++#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA ++ /* enable extension fifo for paced DMA transfers */ ++ sdhci_bcm2708_writel(host, 1, REG_EXRDFIFO_EN); ++ sdhci_bcm2708_writel(host, 4, REG_EXRDFIFO_CFG); ++#endif ++ + printk(KERN_INFO "%s: BCM2708 SDHC host at 0x%08llx DMA %d IRQ %d\n", + mmc_hostname(host->mmc), (unsigned long long)iomem->start, + host_priv->dma_chan, host_priv->dma_irq); @@ -8047,12 +8177,27 @@ index 0000000..d8ef77c +module_init(sdhci_drv_init); +module_exit(sdhci_drv_exit); + ++module_param(allow_highspeed, bool, 0444); ++module_param(emmc_clock_freq, int, 0444); ++module_param(sync_after_dma, bool, 0444); ++module_param(missing_status, bool, 0444); ++module_param(cycle_delay, int, 0444); ++module_param(extra_messages, bool, 0444); ++ +MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver"); +MODULE_AUTHOR("Broadcom "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRIVER_NAME); ++ ++MODULE_PARM_DESC(allow_highspeed, "Allow high speed transfers modes"); ++MODULE_PARM_DESC(emmc_clock_freq, "Specify the speed of emmc clock"); ++MODULE_PARM_DESC(sync_after_dma, "Block in driver until dma complete"); ++MODULE_PARM_DESC(missing_status, "Use the missing status quirk"); ++MODULE_PARM_DESC(extra_messages, "Enable more sdcard warning messages"); ++ ++ diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index 9a79fc4..4be4fc8 100644 +index 47055f3..e47c346 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -28,6 +28,7 @@ @@ -8063,7 +8208,7 @@ index 9a79fc4..4be4fc8 100644 #include #include "sdhci.h" -@@ -326,7 +327,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host) +@@ -312,7 +313,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host) u32 uninitialized_var(scratch); u8 *buf; @@ -8072,7 +8217,7 @@ index 9a79fc4..4be4fc8 100644 blksize = host->data->blksz; chunk = 0; -@@ -371,7 +372,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host) +@@ -357,7 +358,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host) u32 scratch; u8 *buf; @@ -8081,7 +8226,7 @@ index 9a79fc4..4be4fc8 100644 blksize = host->data->blksz; chunk = 0; -@@ -410,19 +411,28 @@ static void sdhci_write_block_pio(struct sdhci_host *host) +@@ -396,19 +397,28 @@ static void sdhci_write_block_pio(struct sdhci_host *host) local_irq_restore(flags); } @@ -8113,7 +8258,7 @@ index 9a79fc4..4be4fc8 100644 /* * Some controllers (JMicron JMB38x) mess up the buffer bits -@@ -433,7 +443,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host) +@@ -419,7 +429,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host) (host->data->blocks == 1)) mask = ~0; @@ -8122,12 +8267,13 @@ index 9a79fc4..4be4fc8 100644 if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY) udelay(100); -@@ -445,9 +455,11 @@ static void sdhci_transfer_pio(struct sdhci_host *host) +@@ -431,9 +441,12 @@ static void sdhci_transfer_pio(struct sdhci_host *host) host->blocks--; if (host->blocks == 0) break; + state = sdhci_readl(host, SDHCI_PRESENT_STATE); + available = state & mask; ++ break; } - DBG("PIO transfer complete.\n"); @@ -8135,7 +8281,7 @@ index 9a79fc4..4be4fc8 100644 } static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) -@@ -720,7 +732,9 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host) +@@ -698,7 +711,9 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host) u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL; u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR; @@ -8143,10 +8289,10 @@ index 9a79fc4..4be4fc8 100644 + /* platform DMA will begin on receipt of PIO irqs */ + if ((host->flags & SDHCI_REQ_USE_DMA) && + !(host->flags & SDHCI_USE_PLATDMA)) - sdhci_clear_set_irqs(host, pio_irqs, dma_irqs); + host->ier = (host->ier & ~pio_irqs) | dma_irqs; else - sdhci_clear_set_irqs(host, dma_irqs, pio_irqs); -@@ -752,44 +766,25 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) + host->ier = (host->ier & ~dma_irqs) | pio_irqs; +@@ -733,44 +748,25 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) host->data_early = 0; host->data->bytes_xfered = 0; @@ -8199,7 +8345,7 @@ index 9a79fc4..4be4fc8 100644 int broken, i; struct scatterlist *sg; -@@ -848,7 +843,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) +@@ -829,7 +825,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) */ WARN_ON(1); host->flags &= ~SDHCI_REQ_USE_DMA; @@ -8209,7 +8355,7 @@ index 9a79fc4..4be4fc8 100644 WARN_ON(sg_cnt != 1); sdhci_writel(host, sg_dma_address(data->sg), SDHCI_DMA_ADDRESS); -@@ -864,11 +860,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) +@@ -845,11 +842,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) if (host->version >= SDHCI_SPEC_200) { ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; @@ -8223,7 +8369,7 @@ index 9a79fc4..4be4fc8 100644 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } -@@ -925,7 +923,8 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, +@@ -906,7 +905,8 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, if (data->flags & MMC_DATA_READ) mode |= SDHCI_TRNS_READ; @@ -8233,7 +8379,7 @@ index 9a79fc4..4be4fc8 100644 mode |= SDHCI_TRNS_DMA; sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); -@@ -941,13 +940,16 @@ static void sdhci_finish_data(struct sdhci_host *host) +@@ -922,13 +922,16 @@ static void sdhci_finish_data(struct sdhci_host *host) host->data = NULL; if (host->flags & SDHCI_REQ_USE_DMA) { @@ -8254,7 +8400,7 @@ index 9a79fc4..4be4fc8 100644 } /* -@@ -1000,6 +1002,12 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) +@@ -981,6 +984,12 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) mask |= SDHCI_DATA_INHIBIT; @@ -8267,7 +8413,7 @@ index 9a79fc4..4be4fc8 100644 /* We shouldn't wait for data inihibit for stop commands, even though they might use busy signaling */ if (host->mrq->data && (cmd == host->mrq->data->stop)) -@@ -1017,6 +1025,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) +@@ -998,6 +1007,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) timeout--; mdelay(1); } @@ -8276,36 +8422,7 @@ index 9a79fc4..4be4fc8 100644 timeout = jiffies; 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); - - host->cmd = cmd; -+ if (host->last_cmdop == MMC_APP_CMD) -+ host->last_cmdop = -cmd->opcode; -+ else -+ host->last_cmdop = cmd->opcode; - - sdhci_prepare_data(host, cmd); - -@@ -1505,7 +1519,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) - else - ctrl &= ~SDHCI_CTRL_HISPD; - -- if (host->version >= SDHCI_SPEC_300) { -+ if (host->version >= SDHCI_SPEC_300 && !(host->ops->uhs_broken)) { - u16 clk, ctrl_2; - - /* In case of UHS-I modes, set High Speed Enable */ -@@ -2203,7 +2217,7 @@ static void sdhci_timeout_timer(unsigned long data) - - if (host->mrq) { - pr_err("%s: Timeout waiting for hardware " -- "interrupt.\n", mmc_hostname(host->mmc)); -+ "interrupt - cmd%d.\n", mmc_hostname(host->mmc), host->last_cmdop); - sdhci_dumpregs(host); - - if (host->data) { -@@ -2248,10 +2262,13 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) +@@ -2205,10 +2216,13 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) BUG_ON(intmask == 0); if (!host->cmd) { @@ -8319,7 +8436,7 @@ index 9a79fc4..4be4fc8 100644 return; } -@@ -2321,6 +2338,19 @@ static void sdhci_show_adma_error(struct sdhci_host *host) +@@ -2278,6 +2292,19 @@ static void sdhci_show_adma_error(struct sdhci_host *host) static void sdhci_show_adma_error(struct sdhci_host *host) { } #endif @@ -8339,7 +8456,7 @@ index 9a79fc4..4be4fc8 100644 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { u32 command; -@@ -2350,23 +2380,39 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +@@ -2307,10 +2334,13 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } @@ -8353,48 +8470,12 @@ index 9a79fc4..4be4fc8 100644 return; } - - if (intmask & SDHCI_INT_DATA_TIMEOUT) - host->data->error = -ETIMEDOUT; -- else if (intmask & SDHCI_INT_DATA_END_BIT) -+ else if (intmask & SDHCI_INT_DATA_END_BIT) { -+ DBG("end error in cmd %d\n", host->last_cmdop); -+ if (host->ops->spurious_crc_acmd51 && -+ host->last_cmdop == -SD_APP_SEND_SCR) { -+ DBG("ignoring spurious data_end_bit error\n"); -+ intmask = SDHCI_INT_DATA_AVAIL|SDHCI_INT_DATA_END; -+ } else - host->data->error = -EILSEQ; -- else if ((intmask & SDHCI_INT_DATA_CRC) && -+ } else if ((intmask & SDHCI_INT_DATA_CRC) && - SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) -- != MMC_BUS_TEST_R) -+ != MMC_BUS_TEST_R) { -+ DBG("crc error in cmd %d\n", host->last_cmdop); -+ if (host->ops->spurious_crc_acmd51 && -+ host->last_cmdop == -SD_APP_SEND_SCR) { -+ DBG("ignoring spurious data_crc_bit error\n"); -+ intmask = SDHCI_INT_DATA_AVAIL|SDHCI_INT_DATA_END; -+ } else { - host->data->error = -EILSEQ; -- else if (intmask & SDHCI_INT_ADMA_ERROR) { -+ } -+ } else if (intmask & SDHCI_INT_ADMA_ERROR) { - pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); - sdhci_show_adma_error(host); - host->data->error = -EIO; -@@ -2374,11 +2420,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) - host->ops->adma_workaround(host, intmask); - } - -- if (host->data->error) -+ if (host->data->error) { -+ DBG("finish request early on error %d\n", host->data->error); +@@ -2334,8 +2364,14 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) + if (host->data->error) sdhci_finish_data(host); -- else { + else { - if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) - sdhci_transfer_pio(host); -+ } else { + if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) { + if (host->flags & SDHCI_REQ_USE_DMA) { + /* possible only in PLATDMA mode */ @@ -8406,7 +8487,7 @@ index 9a79fc4..4be4fc8 100644 /* * We currently don't do anything fancy with DMA -@@ -2407,18 +2460,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +@@ -2364,18 +2400,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); } @@ -8427,45 +8508,45 @@ index 9a79fc4..4be4fc8 100644 } } -@@ -2472,6 +2515,22 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) - tasklet_schedule(&host->card_tasklet); - } +@@ -2438,6 +2464,22 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) + result = IRQ_WAKE_THREAD; + } -+ if (intmask & SDHCI_INT_ERROR_MASK & ~SDHCI_INT_ERROR) -+ DBG("controller reports error 0x%x -" -+ "%s%s%s%s%s%s%s%s%s%s", -+ intmask, -+ intmask & SDHCI_INT_TIMEOUT? " timeout": "", -+ intmask & SDHCI_INT_CRC ? " crc": "", -+ intmask & SDHCI_INT_END_BIT? " endbit": "", -+ intmask & SDHCI_INT_INDEX? " index": "", -+ intmask & SDHCI_INT_DATA_TIMEOUT? " data_timeout": "", -+ intmask & SDHCI_INT_DATA_CRC? " data_crc": "", -+ intmask & SDHCI_INT_DATA_END_BIT? " data_endbit": "", -+ intmask & SDHCI_INT_BUS_POWER? " buspower": "", -+ intmask & SDHCI_INT_ACMD12ERR? " acmd12": "", -+ intmask & SDHCI_INT_ADMA_ERROR? " adma": "" -+ ); ++ if (intmask & SDHCI_INT_ERROR_MASK & ~SDHCI_INT_ERROR) ++ DBG("controller reports error 0x%x -" ++ "%s%s%s%s%s%s%s%s%s%s", ++ intmask, ++ intmask & SDHCI_INT_TIMEOUT? " timeout": "", ++ intmask & SDHCI_INT_CRC ? " crc": "", ++ intmask & SDHCI_INT_END_BIT? " endbit": "", ++ intmask & SDHCI_INT_INDEX? " index": "", ++ intmask & SDHCI_INT_DATA_TIMEOUT? " data_timeout": "", ++ intmask & SDHCI_INT_DATA_CRC? " data_crc": "", ++ intmask & SDHCI_INT_DATA_END_BIT? " data_endbit": "", ++ intmask & SDHCI_INT_BUS_POWER? " buspower": "", ++ intmask & SDHCI_INT_ACMD12ERR? " acmd12": "", ++ intmask & SDHCI_INT_ADMA_ERROR? " adma": "" ++ ); + - if (intmask & SDHCI_INT_CMD_MASK) { - sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, - SDHCI_INT_STATUS); -@@ -2486,7 +2545,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) + if (intmask & SDHCI_INT_CMD_MASK) + sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); - intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); +@@ -2459,6 +2501,14 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) + SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER | + SDHCI_INT_CARD_INT); -- intmask &= ~SDHCI_INT_ERROR; -+ if (intmask & SDHCI_INT_ERROR_MASK) { -+ /* collect any uncovered errors */ -+ sdhci_writel(host, intmask & SDHCI_INT_ERROR_MASK, -+ SDHCI_INT_STATUS); -+ } ++ if (intmask & SDHCI_INT_ERROR_MASK) { ++ /* collect any uncovered errors */ ++ sdhci_writel(host, intmask & SDHCI_INT_ERROR_MASK, ++ SDHCI_INT_STATUS); ++ } + -+ intmask &= ~SDHCI_INT_ERROR_MASK; - - if (intmask & SDHCI_INT_BUS_POWER) { - pr_err("%s: Card is consuming too much power!\n", -@@ -2599,7 +2664,8 @@ int sdhci_resume_host(struct sdhci_host *host) ++ intmask &= ~SDHCI_INT_ERROR_MASK; ++ + if (intmask) { + unexpected |= intmask; + sdhci_writel(host, intmask, SDHCI_INT_STATUS); +@@ -2571,7 +2621,8 @@ int sdhci_resume_host(struct sdhci_host *host) { int ret = 0; @@ -8475,7 +8556,7 @@ index 9a79fc4..4be4fc8 100644 if (host->ops->enable_dma) host->ops->enable_dma(host); } -@@ -2830,14 +2896,16 @@ int sdhci_add_host(struct sdhci_host *host) +@@ -2802,14 +2853,16 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_ADMA; } @@ -8494,7 +8575,7 @@ index 9a79fc4..4be4fc8 100644 } } } -@@ -3264,6 +3332,7 @@ int sdhci_add_host(struct sdhci_host *host) +@@ -3249,6 +3302,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)), @@ -8503,13 +8584,13 @@ index 9a79fc4..4be4fc8 100644 (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h -index 0a3ed01..6857875 100644 +index 4a5cd5e..ffa4175 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h -@@ -290,6 +290,20 @@ struct sdhci_ops { - void (*platform_reset_exit)(struct sdhci_host *host, u8 mask); +@@ -288,6 +288,17 @@ struct sdhci_ops { + void (*reset)(struct sdhci_host *host, u8 mask); int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode); - int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); + void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); + + int (*pdma_able)(struct sdhci_host *host, + struct mmc_data *data); @@ -8519,15 +8600,12 @@ index 0a3ed01..6857875 100644 + void (*pdma_reset)(struct sdhci_host *host, + struct mmc_data *data); + unsigned int (*extra_ints)(struct sdhci_host *host); -+ unsigned int (*spurious_crc_acmd51)(struct sdhci_host *host); -+ unsigned int (*voltage_broken)(struct sdhci_host *host); -+ unsigned int (*uhs_broken)(struct sdhci_host *host); + unsigned int (*missing_status)(struct sdhci_host *host); + void (*hw_reset)(struct sdhci_host *host); - void (*platform_suspend)(struct sdhci_host *host); - void (*platform_resume)(struct sdhci_host *host); -@@ -403,6 +417,29 @@ extern int sdhci_resume_host(struct sdhci_host *host); + void (*adma_workaround)(struct sdhci_host *host, u32 intmask); + void (*platform_init)(struct sdhci_host *host); +@@ -409,6 +420,29 @@ extern int sdhci_resume_host(struct sdhci_host *host); extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); #endif @@ -8558,7 +8636,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 c2ee793..3196890 100644 +index 0e26dcb..adc0e47 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -84,7 +84,7 @@ struct vendor_data { @@ -8570,11 +8648,23 @@ index c2ee793..3196890 100644 } static struct vendor_data vendor_arm = { +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index 7960424..b82f5cd 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -283,6 +283,7 @@ struct mmc_host { + #define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \ + MMC_CAP2_HS400_1_2V) + #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17) ++#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 7be12b8..a968bd6 100644 +index 08abe99..544da76 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h -@@ -135,6 +135,7 @@ struct sdhci_host { +@@ -131,6 +131,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 */ @@ -8582,22 +8672,14 @@ index 7be12b8..a968bd6 100644 unsigned int version; /* SDHCI spec. version */ -@@ -150,6 +151,7 @@ struct sdhci_host { - - struct mmc_request *mrq; /* Current request */ - struct mmc_command *cmd; /* Current command */ -+ int last_cmdop; /* Opcode of last cmd sent */ - struct mmc_data *data; /* Current data request */ - unsigned int data_early:1; /* Data finished before cmd */ - -- 2.0.3 -From 53ef386cda383e7016807a97345f52b8ba0c8e64 Mon Sep 17 00:00:00 2001 +From a7620c972ac833ec67feafd57c59a7b9b3244aba Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 22:20:24 +0100 -Subject: [PATCH 02/81] Add quick config. +Subject: [PATCH 02/69] Add quick config. This is designed for quick compiling when developing. No modules are needed and it includes all Pi specific drivers @@ -8813,10 +8895,10 @@ index 0000000..e5efe75 2.0.3 -From 4a960a086e5c561e036a573b7bbe5cf385c54a50 Mon Sep 17 00:00:00 2001 +From c4766da426e90cc933773a962a22948a4ca573f2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 03/81] Add dwc_otg driver +Subject: [PATCH 03/69] Add dwc_otg driver Signed-off-by: popcornmix --- @@ -8945,7 +9027,7 @@ Signed-off-by: popcornmix create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile -index 1ae2bf3..c4a45aa 100644 +index 3cba892..7aec507 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/ @@ -12955,10 +13037,10 @@ index 0000000..a896d73 +} +module_exit(fsg_cleanup); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index 3d9e540..e881817 100644 +index 03314f8..16790e3 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig -@@ -685,6 +685,19 @@ config USB_HWA_HCD +@@ -713,6 +713,19 @@ config USB_HWA_HCD To compile this driver a module, choose M here: the module will be called "hwa-hc". @@ -12979,10 +13061,10 @@ index 3d9e540..e881817 100644 tristate "i.MX21 HCD support" depends on ARM && ARCH_MXC diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 7530468..876f024 100644 +index af89a90..6e624e9 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile -@@ -63,6 +63,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o +@@ -66,6 +66,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o @@ -65888,10 +65970,10 @@ index 0000000..cdc9963 2.0.3 -From 7ad8e6e32a563fc3d9de0d53644b96b8e9b19fed Mon Sep 17 00:00:00 2001 +From 53fe7eb309b1efcf96f9010622d698a41d7fe928 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 04/81] bcm2708 watchdog driver +Subject: [PATCH 04/69] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -65902,10 +65984,10 @@ Signed-off-by: popcornmix create mode 100644 drivers/watchdog/bcm2708_wdog.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index 74ec8fc..dbe8bf8 100644 +index 76dd541..a29b6b4 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig -@@ -411,6 +411,12 @@ config RETU_WATCHDOG +@@ -413,6 +413,12 @@ config RETU_WATCHDOG To compile this driver as a module, choose M here: the module will be called retu_wdt. @@ -65919,7 +66001,7 @@ index 74ec8fc..dbe8bf8 100644 tristate "MOXART watchdog" depends on ARCH_MOXART diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile -index 1b5f3d5..f3730ed 100644 +index 468c320..c9a497a 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o @@ -66322,10 +66404,10 @@ index 0000000..8a27d68 2.0.3 -From 7f410ce72dc3b246c9ce8c8a8552fa195054994e Mon Sep 17 00:00:00 2001 +From 40a7b010c351b4e9b12e1a307a08fc2ed5cc8638 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:55:09 +0100 -Subject: [PATCH 05/81] bcm2708 framebuffer driver +Subject: [PATCH 05/69] bcm2708 framebuffer driver Signed-off-by: popcornmix --- @@ -66337,7 +66419,7 @@ Signed-off-by: popcornmix create mode 100644 drivers/video/fbdev/bcm2708_fb.c diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig -index e1f4727..541716e 100644 +index 59c98bfd..76c3235 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -220,6 +220,20 @@ config FB_TILEBLITTING @@ -69372,10 +69454,814 @@ index 3c14e43..7626beb 100644 2.0.3 -From ea23a7eee3f8ddb98b8e0cdf47828973e3a5798a Mon Sep 17 00:00:00 2001 +From d5e4fe4b752393809af327001f3be62c430a169c Mon Sep 17 00:00:00 2001 +From: Harm Hanemaaijer +Date: Thu, 20 Jun 2013 20:21:39 +0200 +Subject: [PATCH 06/69] 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 +console monochrome imageblit function used to draw console text is +suboptimal for common pixel depths such as 16bpp and 32bpp. The existing +code is quite general and can deal with several pixel depths. By creating +special case functions for 16bpp and 32bpp, by far the most common pixel +formats used on modern systems, a significant speed-up is attained +which can be readily felt on ARM-based devices like the Raspberry Pi +and the Allwinner platform, but should help any platform using the +fb layer. + +The special case functions allow constant folding, eliminating a number +of instructions including divide operations, and allow the use of an +unrolled loop, eliminating instructions with a variable shift size, +reducing source memory access instructions, and eliminating excessive +branching. These unrolled loops also allow much better code optimization +by the C compiler. The code that selects which optimized variant is used +is also simplified, eliminating integer divide instructions. + +The speed-up, measured by timing 'cat file.txt' in the console, varies +between 40% and 70%, when testing on the Raspberry Pi and Allwinner +ARM-based platforms, depending on font size and the pixel depth, with +the greater benefit for 32bpp. + +Signed-off-by: Harm Hanemaaijer +--- + drivers/video/fbdev/core/cfbimgblt.c | 152 +++++++++++++++++++++++++++++++++-- + 1 file changed, 147 insertions(+), 5 deletions(-) + +diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c +index a2bb276..436494f 100644 +--- 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 + * the native cpu endians. I also need to deal with MSB position in the word. ++ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013: ++ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are ++ * significantly faster than the previous implementation. ++ * - Simplify the fast/slow_imageblit selection code, avoiding integer ++ * divides. + */ + #include + #include +@@ -262,6 +267,133 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * + } + } + ++/* ++ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded ++ * into the code, main loop unrolled. ++ */ ++ ++static inline void fast_imageblit16(const struct fb_image *image, ++ struct fb_info *p, u8 __iomem * dst1, ++ u32 fgcolor, u32 bgcolor) ++{ ++ u32 fgx = fgcolor, bgx = bgcolor; ++ u32 spitch = (image->width + 7) / 8; ++ u32 end_mask, eorx; ++ const char *s = image->data, *src; ++ u32 __iomem *dst; ++ const u32 *tab = NULL; ++ int i, j, k; ++ ++ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; ++ ++ fgx <<= 16; ++ bgx <<= 16; ++ fgx |= fgcolor; ++ bgx |= bgcolor; ++ ++ eorx = fgx ^ bgx; ++ k = image->width / 2; ++ ++ for (i = image->height; i--;) { ++ dst = (u32 __iomem *) dst1; ++ src = s; ++ ++ j = k; ++ while (j >= 4) { ++ u8 bits = *src; ++ end_mask = tab[(bits >> 6) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 4) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 2) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[bits & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ src++; ++ j -= 4; ++ } ++ if (j != 0) { ++ u8 bits = *src; ++ end_mask = tab[(bits >> 6) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ if (j >= 2) { ++ end_mask = tab[(bits >> 4) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ if (j == 3) { ++ end_mask = tab[(bits >> 2) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst); ++ } ++ } ++ } ++ dst1 += p->fix.line_length; ++ s += spitch; ++ } ++} ++ ++/* ++ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded ++ * into the code, main loop unrolled. ++ */ ++ ++static inline void fast_imageblit32(const struct fb_image *image, ++ struct fb_info *p, u8 __iomem * dst1, ++ u32 fgcolor, u32 bgcolor) ++{ ++ u32 fgx = fgcolor, bgx = bgcolor; ++ u32 spitch = (image->width + 7) / 8; ++ u32 end_mask, eorx; ++ const char *s = image->data, *src; ++ u32 __iomem *dst; ++ const u32 *tab = NULL; ++ int i, j, k; ++ ++ tab = cfb_tab32; ++ ++ eorx = fgx ^ bgx; ++ k = image->width; ++ ++ for (i = image->height; i--;) { ++ dst = (u32 __iomem *) dst1; ++ src = s; ++ ++ j = k; ++ while (j >= 8) { ++ u8 bits = *src; ++ end_mask = tab[(bits >> 7) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 6) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 5) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 4) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 3) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 2) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 1) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[bits & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ src++; ++ j -= 8; ++ } ++ if (j != 0) { ++ u32 bits = (u32) * src; ++ while (j > 1) { ++ end_mask = tab[(bits >> 7) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ bits <<= 1; ++ j--; ++ } ++ end_mask = tab[(bits >> 7) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst); ++ } ++ dst1 += p->fix.line_length; ++ s += spitch; ++ } ++} ++ + void cfb_imageblit(struct fb_info *p, const struct fb_image *image) + { + u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; +@@ -294,11 +426,21 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) + bgcolor = image->bg_color; + } + +- if (32 % bpp == 0 && !start_index && !pitch_index && +- ((width & (32/bpp-1)) == 0) && +- bpp >= 8 && bpp <= 32) +- fast_imageblit(image, p, dst1, fgcolor, bgcolor); +- else ++ if (!start_index && !pitch_index) { ++ if (bpp == 32) ++ fast_imageblit32(image, p, dst1, fgcolor, ++ bgcolor); ++ else if (bpp == 16 && (width & 1) == 0) ++ fast_imageblit16(image, p, dst1, fgcolor, ++ bgcolor); ++ else if (bpp == 8 && (width & 3) == 0) ++ fast_imageblit(image, p, dst1, fgcolor, ++ bgcolor); ++ else ++ slow_imageblit(image, p, dst1, fgcolor, ++ bgcolor, ++ start_index, pitch_index); ++ } else + slow_imageblit(image, p, dst1, fgcolor, bgcolor, + start_index, pitch_index); + } else +-- +2.0.3 + + +From 2319763577aac9e45e0fc3af8c2a51f56e081c08 Mon Sep 17 00:00:00 2001 +From: Siarhei Siamashka +Date: Mon, 17 Jun 2013 13:32:11 +0300 +Subject: [PATCH 07/69] fbdev: add FBIOCOPYAREA ioctl + +Based on the patch authored by Ali Gholami Rudi at + https://lkml.org/lkml/2009/7/13/153 + +Provide an ioctl for userspace applications, but only if this operation +is hardware accelerated (otherwide it does not make any sense). + +Signed-off-by: Siarhei Siamashka +--- + drivers/video/fbdev/core/fbmem.c | 30 ++++++++++++++++++++++++++++++ + include/uapi/linux/fb.h | 5 +++++ + 2 files changed, 35 insertions(+) + +diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c +index b5e85f6..dff4c47 100644 +--- a/drivers/video/fbdev/core/fbmem.c ++++ b/drivers/video/fbdev/core/fbmem.c +@@ -1084,6 +1084,25 @@ fb_blank(struct fb_info *info, int blank) + } + EXPORT_SYMBOL(fb_blank); + ++static int fb_copyarea_user(struct fb_info *info, ++ struct fb_copyarea *copy) ++{ ++ int ret = 0; ++ if (!lock_fb_info(info)) ++ return -ENODEV; ++ if (copy->dx + copy->width > info->var.xres || ++ copy->sx + copy->width > info->var.xres || ++ copy->dy + copy->height > info->var.yres || ++ copy->sy + copy->height > info->var.yres) { ++ ret = -EINVAL; ++ goto out; ++ } ++ info->fbops->fb_copyarea(info, copy); ++out: ++ unlock_fb_info(info); ++ return ret; ++} ++ + static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) + { +@@ -1094,6 +1113,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, + struct fb_cmap cmap_from; + struct fb_cmap_user cmap; + struct fb_event event; ++ struct fb_copyarea copy; + void __user *argp = (void __user *)arg; + long ret = 0; + +@@ -1211,6 +1231,15 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, + unlock_fb_info(info); + console_unlock(); + break; ++ case FBIOCOPYAREA: ++ if (info->flags & FBINFO_HWACCEL_COPYAREA) { ++ /* only provide this ioctl if it is accelerated */ ++ if (copy_from_user(©, argp, sizeof(copy))) ++ return -EFAULT; ++ ret = fb_copyarea_user(info, ©); ++ break; ++ } ++ /* fall through */ + default: + if (!lock_fb_info(info)) + return -ENODEV; +@@ -1365,6 +1394,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, + case FBIOPAN_DISPLAY: + case FBIOGET_CON2FBMAP: + case FBIOPUT_CON2FBMAP: ++ case FBIOCOPYAREA: + arg = (unsigned long) compat_ptr(arg); + case FBIOBLANK: + ret = do_fb_ioctl(info, cmd, arg); +diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h +index fb795c3..fa72af0 100644 +--- a/include/uapi/linux/fb.h ++++ b/include/uapi/linux/fb.h +@@ -34,6 +34,11 @@ + #define FBIOPUT_MODEINFO 0x4617 + #define FBIOGET_DISPINFO 0x4618 + #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) ++/* ++ * HACK: use 'z' in order not to clash with any other ioctl numbers which might ++ * be concurrently added to the mainline kernel ++ */ ++#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea) + + #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ + #define FB_TYPE_PLANES 1 /* Non interleaved planes */ +-- +2.0.3 + + +From 54bd9aef58aa6e7c33d7047bb2c157c8bc774318 Mon Sep 17 00:00:00 2001 +From: Siarhei Siamashka +Date: Mon, 17 Jun 2013 16:00:25 +0300 +Subject: [PATCH 08/69] 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 +settings for better performance. + +For now busylooping only. IRQ support might be added later. +With non-overclocked Raspberry Pi, the performance is ~360 MB/s +for simple copy or ~260 MB/s for two-pass copy (used when dragging +windows to the right). + +In the case of using DMA channel 0, the performance improves +to ~440 MB/s. + +For comparison, VFP optimized CPU copy can only do ~114 MB/s in +the same conditions (hindered by reading uncached source buffer). + +Signed-off-by: Siarhei Siamashka + +bcm2708_fb: report number of dma copies + +Add a counter (exported via debugfs) reporting the +number of dma copies that the framebuffer driver +has done, in order to help evaluate different +optimization strategies. + +Signed-off-by: Luke Diamand + +bcm2708_fb: use IRQ for DMA copies + +The copyarea ioctl() uses DMA to speed things along. This +was busy-waiting for completion. This change supports using +an interrupt instead for larger transfers. For small +transfers, busy-waiting is still likely to be faster. + +Signed-off-by: Luke Diamand + +fb: distinguish physical and bus addresses +--- + arch/arm/mach-bcm2708/dma.c | 8 + + arch/arm/mach-bcm2708/include/mach/dma.h | 2 + + drivers/video/fbdev/bcm2708_fb.c | 280 ++++++++++++++++++++++++++++++- + 3 files changed, 283 insertions(+), 7 deletions(-) + +diff --git a/arch/arm/mach-bcm2708/dma.c b/arch/arm/mach-bcm2708/dma.c +index 51d147a..1da2413 100644 +--- a/arch/arm/mach-bcm2708/dma.c ++++ b/arch/arm/mach-bcm2708/dma.c +@@ -83,6 +83,14 @@ extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) + + EXPORT_SYMBOL_GPL(bcm_dma_start); + ++extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) ++{ ++ dsb(); ++ ++ return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; ++} ++EXPORT_SYMBOL_GPL(bcm_dma_is_busy); ++ + /* Complete an ongoing DMA (assuming its results are to be ignored) + Does nothing if there is no DMA in progress. + This routine waits for the current AXI transfer to complete before +diff --git a/arch/arm/mach-bcm2708/include/mach/dma.h b/arch/arm/mach-bcm2708/include/mach/dma.h +index ac7a4a0..6d2f9a0 100644 +--- a/arch/arm/mach-bcm2708/include/mach/dma.h ++++ b/arch/arm/mach-bcm2708/include/mach/dma.h +@@ -62,11 +62,13 @@ struct bcm2708_dma_cb { + unsigned long next; + unsigned long pad[2]; + }; ++struct scatterlist; + + extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); + extern void bcm_dma_start(void __iomem *dma_chan_base, + dma_addr_t control_block); + extern void bcm_dma_wait_idle(void __iomem *dma_chan_base); ++extern bool bcm_dma_is_busy(void __iomem *dma_chan_base); + 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/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c +index 54cd760..b3b1e04 100644 +--- a/drivers/video/fbdev/bcm2708_fb.c ++++ b/drivers/video/fbdev/bcm2708_fb.c +@@ -21,13 +21,16 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include + ++#include + #include + #include + +@@ -51,6 +54,10 @@ static int fbheight = 480; /* module parameter */ + static int fbdepth = 16; /* module parameter */ + static int fbswap = 0; /* module parameter */ + ++static u32 dma_busy_wait_threshold = 1<<15; ++module_param(dma_busy_wait_threshold, int, 0644); ++MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area"); ++ + /* this data structure describes each frame buffer device we find */ + + struct fbinfo_s { +@@ -62,16 +69,74 @@ struct fbinfo_s { + u16 cmap[256]; + }; + ++struct bcm2708_fb_stats { ++ struct debugfs_regset32 regset; ++ u32 dma_copies; ++ u32 dma_irqs; ++}; ++ + struct bcm2708_fb { + struct fb_info fb; + struct platform_device *dev; + struct fbinfo_s *info; + dma_addr_t dma; + u32 cmap[16]; ++ int dma_chan; ++ int dma_irq; ++ void __iomem *dma_chan_base; ++ void *cb_base; /* DMA control blocks */ ++ dma_addr_t cb_handle; ++ struct dentry *debugfs_dir; ++ wait_queue_head_t dma_waitq; ++ struct bcm2708_fb_stats stats; ++ unsigned long fb_bus_address; + }; + + #define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb) + ++static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb) ++{ ++ debugfs_remove_recursive(fb->debugfs_dir); ++ fb->debugfs_dir = NULL; ++} ++ ++static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb) ++{ ++ static struct debugfs_reg32 stats_registers[] = { ++ { ++ "dma_copies", ++ offsetof(struct bcm2708_fb_stats, dma_copies) ++ }, ++ { ++ "dma_irqs", ++ offsetof(struct bcm2708_fb_stats, dma_irqs) ++ }, ++ }; ++ ++ fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL); ++ if (!fb->debugfs_dir) { ++ pr_warn("%s: could not create debugfs entry\n", ++ __func__); ++ return -EFAULT; ++ } ++ ++ fb->stats.regset.regs = stats_registers; ++ fb->stats.regset.nregs = ARRAY_SIZE(stats_registers); ++ fb->stats.regset.base = &fb->stats; ++ ++ if (!debugfs_create_regset32( ++ "stats", 0444, fb->debugfs_dir, &fb->stats.regset)) { ++ pr_warn("%s: could not create statistics registers\n", ++ __func__); ++ goto fail; ++ } ++ return 0; ++ ++fail: ++ bcm2708_fb_debugfs_deinit(fb); ++ return -EFAULT; ++} ++ + static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var) + { + int ret = 0; +@@ -250,13 +315,15 @@ static int bcm2708_fb_set_par(struct fb_info *info) + else + fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + ++ 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(); +@@ -267,7 +334,7 @@ static int bcm2708_fb_set_par(struct fb_info *info) + } + 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); + +@@ -322,11 +389,148 @@ static void bcm2708_fb_fillrect(struct fb_info *info, + cfb_fillrect(info, rect); + } + ++/* A helper function for configuring dma control block */ ++static void set_dma_cb(struct bcm2708_dma_cb *cb, ++ int burst_size, ++ dma_addr_t dst, ++ int dst_stride, ++ dma_addr_t src, ++ int src_stride, ++ int w, ++ int h) ++{ ++ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH | ++ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH | ++ BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE; ++ cb->dst = dst; ++ cb->src = src; ++ /* ++ * This is not really obvious from the DMA documentation, ++ * but the top 16 bits must be programmmed to "height -1" ++ * and not "height" in 2D mode. ++ */ ++ cb->length = ((h - 1) << 16) | w; ++ cb->stride = ((dst_stride - w) << 16) | (u16)(src_stride - w); ++ cb->pad[0] = 0; ++ cb->pad[1] = 0; ++} ++ + static void bcm2708_fb_copyarea(struct fb_info *info, + const struct fb_copyarea *region) + { +- /*print_debug("bcm2708_fb_copyarea\n"); */ +- cfb_copyarea(info, region); ++ struct bcm2708_fb *fb = to_bcm2708(info); ++ struct bcm2708_dma_cb *cb = fb->cb_base; ++ int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; ++ /* Channel 0 supports larger bursts and is a bit faster */ ++ int burst_size = (fb->dma_chan == 0) ? 8 : 2; ++ int pixels = region->width * region->height; ++ ++ /* Fallback to cfb_copyarea() if we don't like something */ ++ if (bytes_per_pixel > 4 || ++ info->var.xres * info->var.yres > 1920 * 1200 || ++ region->width <= 0 || region->width > info->var.xres || ++ region->height <= 0 || region->height > info->var.yres || ++ region->sx < 0 || region->sx >= info->var.xres || ++ region->sy < 0 || region->sy >= info->var.yres || ++ region->dx < 0 || region->dx >= info->var.xres || ++ region->dy < 0 || region->dy >= info->var.yres || ++ region->sx + region->width > info->var.xres || ++ region->dx + region->width > info->var.xres || ++ region->sy + region->height > info->var.yres || ++ region->dy + region->height > info->var.yres) { ++ cfb_copyarea(info, region); ++ return; ++ } ++ ++ if (region->dy == region->sy && region->dx > region->sx) { ++ /* ++ * A difficult case of overlapped copy. Because DMA can't ++ * copy individual scanlines in backwards direction, we need ++ * two-pass processing. We do it by programming a chain of dma ++ * control blocks in the first 16K part of the buffer and use ++ * the remaining 48K as the intermediate temporary scratch ++ * buffer. The buffer size is sufficient to handle up to ++ * 1920x1200 resolution at 32bpp pixel depth. ++ */ ++ int y; ++ dma_addr_t control_block_pa = fb->cb_handle; ++ dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024; ++ int scanline_size = bytes_per_pixel * region->width; ++ int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size; ++ ++ for (y = 0; y < region->height; y += scanlines_per_cb) { ++ dma_addr_t src = ++ fb->fb_bus_address + ++ bytes_per_pixel * region->sx + ++ (region->sy + y) * fb->fb.fix.line_length; ++ dma_addr_t dst = ++ fb->fb_bus_address + ++ bytes_per_pixel * region->dx + ++ (region->dy + y) * fb->fb.fix.line_length; ++ ++ if (region->height - y < scanlines_per_cb) ++ scanlines_per_cb = region->height - y; ++ ++ set_dma_cb(cb, burst_size, scratchbuf, scanline_size, ++ src, fb->fb.fix.line_length, ++ scanline_size, scanlines_per_cb); ++ control_block_pa += sizeof(struct bcm2708_dma_cb); ++ cb->next = control_block_pa; ++ cb++; ++ ++ set_dma_cb(cb, burst_size, dst, fb->fb.fix.line_length, ++ scratchbuf, scanline_size, ++ scanline_size, scanlines_per_cb); ++ control_block_pa += sizeof(struct bcm2708_dma_cb); ++ cb->next = control_block_pa; ++ cb++; ++ } ++ /* move the pointer back to the last dma control block */ ++ cb--; ++ } else { ++ /* A single dma control block is enough. */ ++ int sy, dy, stride; ++ if (region->dy <= region->sy) { ++ /* processing from top to bottom */ ++ dy = region->dy; ++ sy = region->sy; ++ stride = fb->fb.fix.line_length; ++ } else { ++ /* processing from bottom to top */ ++ dy = region->dy + region->height - 1; ++ sy = region->sy + region->height - 1; ++ stride = -fb->fb.fix.line_length; ++ } ++ set_dma_cb(cb, burst_size, ++ fb->fb_bus_address + dy * fb->fb.fix.line_length + ++ bytes_per_pixel * region->dx, ++ stride, ++ fb->fb_bus_address + sy * fb->fb.fix.line_length + ++ bytes_per_pixel * region->sx, ++ stride, ++ region->width * bytes_per_pixel, ++ region->height); ++ } ++ ++ /* end of dma control blocks chain */ ++ cb->next = 0; ++ ++ ++ if (pixels < dma_busy_wait_threshold) { ++ bcm_dma_start(fb->dma_chan_base, fb->cb_handle); ++ bcm_dma_wait_idle(fb->dma_chan_base); ++ } else { ++ void __iomem *dma_chan = fb->dma_chan_base; ++ cb->info |= BCM2708_DMA_INT_EN; ++ bcm_dma_start(fb->dma_chan_base, fb->cb_handle); ++ while (bcm_dma_is_busy(dma_chan)) { ++ wait_event_interruptible( ++ fb->dma_waitq, ++ !bcm_dma_is_busy(dma_chan)); ++ } ++ fb->stats.dma_irqs++; ++ } ++ fb->stats.dma_copies++; + } + + static void bcm2708_fb_imageblit(struct fb_info *info, +@@ -336,6 +540,24 @@ static void bcm2708_fb_imageblit(struct fb_info *info, + cfb_imageblit(info, image); + } + ++static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt) ++{ ++ struct bcm2708_fb *fb = cxt; ++ ++ /* FIXME: should read status register to check if this is ++ * actually interrupting us or not, in case this interrupt ++ * ever becomes shared amongst several DMA channels ++ * ++ * readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_IRQ; ++ */ ++ ++ /* acknowledge the interrupt */ ++ writel(BCM2708_DMA_INT, fb->dma_chan_base + BCM2708_DMA_CS); ++ ++ wake_up(&fb->dma_waitq); ++ return IRQ_HANDLED; ++} ++ + static struct fb_ops bcm2708_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = bcm2708_fb_check_var, +@@ -365,7 +587,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb) + fb->dma = dma; + } + fb->fb.fbops = &bcm2708_fb_ops; +- fb->fb.flags = FBINFO_FLAG_DEFAULT; ++ fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA; + fb->fb.pseudo_palette = fb->cmap; + + strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id)); +@@ -396,6 +618,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb) + fb->fb.monspecs.dclkmax = 100000000; + + bcm2708_fb_set_bitfields(&fb->fb.var); ++ init_waitqueue_head(&fb->dma_waitq); + + /* + * Allocate colourmap. +@@ -421,14 +644,45 @@ static int bcm2708_fb_probe(struct platform_device *dev) + struct bcm2708_fb *fb; + int ret; + +- fb = kmalloc(sizeof(struct bcm2708_fb), GFP_KERNEL); ++ fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL); + if (!fb) { + dev_err(&dev->dev, + "could not allocate new bcm2708_fb struct\n"); + ret = -ENOMEM; + goto free_region; + } +- memset(fb, 0, sizeof(struct bcm2708_fb)); ++ ++ bcm2708_fb_debugfs_init(fb); ++ ++ fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K, ++ &fb->cb_handle, GFP_KERNEL); ++ if (!fb->cb_base) { ++ dev_err(&dev->dev, "cannot allocate DMA CBs\n"); ++ ret = -ENOMEM; ++ goto free_fb; ++ } ++ ++ pr_info("BCM2708FB: allocated DMA memory %08x\n", ++ fb->cb_handle); ++ ++ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK, ++ &fb->dma_chan_base, &fb->dma_irq); ++ if (ret < 0) { ++ dev_err(&dev->dev, "couldn't allocate a DMA channel\n"); ++ goto free_cb; ++ } ++ fb->dma_chan = ret; ++ ++ ret = request_irq(fb->dma_irq, bcm2708_fb_dma_irq, ++ 0, "bcm2708_fb dma", fb); ++ if (ret) { ++ pr_err("%s: failed to request DMA irq\n", __func__); ++ goto free_dma_chan; ++ } ++ ++ ++ pr_info("BCM2708FB: allocated DMA channel %d @ %p\n", ++ fb->dma_chan, fb->dma_chan_base); + + fb->dev = dev; + +@@ -438,6 +692,11 @@ static int bcm2708_fb_probe(struct platform_device *dev) + goto out; + } + ++free_dma_chan: ++ bcm_dma_chan_free(fb->dma_chan); ++free_cb: ++ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle); ++free_fb: + kfree(fb); + free_region: + dev_err(&dev->dev, "probe failed, err %d\n", ret); +@@ -455,8 +714,15 @@ static int bcm2708_fb_remove(struct platform_device *dev) + iounmap(fb->fb.screen_base); + unregister_framebuffer(&fb->fb); + ++ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle); ++ bcm_dma_chan_free(fb->dma_chan); ++ + dma_free_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), (void *)fb->info, + fb->dma); ++ bcm2708_fb_debugfs_deinit(fb); ++ ++ free_irq(fb->dma_irq, fb); ++ + kfree(fb); + + return 0; +-- +2.0.3 + + +From 2e1eeed1dd9c1aba1c0c1a6b4ed1efff86cae8c7 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 06/81] bcm2708 vchiq driver +Subject: [PATCH 09/69] bcm2708 vchiq driver Signed-off-by: popcornmix @@ -69458,10 +70344,10 @@ 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 8baff0e..0706e83 100644 +index ee94023..be9232c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig -@@ -524,6 +524,7 @@ source "drivers/misc/carma/Kconfig" +@@ -534,6 +534,7 @@ source "drivers/misc/carma/Kconfig" source "drivers/misc/altera-stapl/Kconfig" source "drivers/misc/mei/Kconfig" source "drivers/misc/vmw_vmci/Kconfig" @@ -69470,7 +70356,7 @@ index 8baff0e..0706e83 100644 source "drivers/misc/genwqe/Kconfig" source "drivers/misc/echo/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index 7eb4b69..8f7c678 100644 +index d59ce12..95f2e53 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_INTEL_MEI) += mei/ @@ -81927,10 +82813,10 @@ index 0000000..b6bfa21 2.0.3 -From 23194c53077fd376e56d8895eb2988dbc398d39e Mon Sep 17 00:00:00 2001 +From 9712514f82d055918a5ca73f2fb7e3873c9ce40b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 12 May 2014 15:12:02 +0100 -Subject: [PATCH 07/81] vchiq: Avoid high load when blocked and unkillable +Subject: [PATCH 10/69] vchiq: Avoid high load when blocked and unkillable vchiq: Include SIGSTOP and SIGCONT in list of signals not-masked by vchiq to allow gdb to work --- @@ -82095,10 +82981,10 @@ index c2eefef..05e7979 100644 2.0.3 -From aa62bfbd15aa087bb217dfdd150d0f0011fed3a5 Mon Sep 17 00:00:00 2001 +From 45c75a9a45e75f750aeff0d08d1396516645d5c6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 08/81] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 11/69] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix --- @@ -83339,7 +84225,7 @@ index 0000000..a635f9f +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Broadcom Corporation"); diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index 8f7c678..524ab7d 100644 +index 95f2e53..33916ff 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -52,7 +52,7 @@ obj-$(CONFIG_INTEL_MEI) += mei/ @@ -83390,25 +84276,44 @@ index 0000000..5325832 2.0.3 -From 4de2e6840a08fb8c01c086f58ebb03d33de4aed8 Mon Sep 17 00:00:00 2001 +From df67b820a9d714d5db7a600bd9792c01036d9126 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 09/81] bcm2708: alsa sound driver +Subject: [PATCH 12/69] bcm2708: alsa sound driver Signed-off-by: popcornmix + +alsa: add mmap support and some cleanups to bcm2835 ALSA driver + +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 +driver extension an appropriate card config is required to make alsa-lib +support the AES parameters for this device. + +snd-bcm2708: Add mutex, improve logging + +Fix for ALSA driver crash + +Avoids an issue when closing and opening vchiq where a message can arrive before service handle has been written + +alsa: reduce severity of expected warning message --- - arch/arm/configs/bcmrpi_cutdown_defconfig | 20 + - arch/arm/configs/bcmrpi_defconfig | 20 + - arch/arm/mach-bcm2708/bcm2708.c | 54 ++ - sound/arm/Kconfig | 7 + - sound/arm/Makefile | 5 + - sound/arm/bcm2835-ctl.c | 200 +++++++ - sound/arm/bcm2835-pcm.c | 409 +++++++++++++++ - sound/arm/bcm2835-vchiq.c | 844 ++++++++++++++++++++++++++++++ - sound/arm/bcm2835.c | 413 +++++++++++++++ - sound/arm/bcm2835.h | 155 ++++++ - sound/arm/vc_vchi_audioserv_defs.h | 116 ++++ - 11 files changed, 2243 insertions(+) + arch/arm/configs/bcmrpi_cutdown_defconfig | 20 + + arch/arm/configs/bcmrpi_defconfig | 20 + + arch/arm/mach-bcm2708/bcm2708.c | 54 ++ + .../interface/vchiq_arm/vchiq_kern_lib.c | 7 +- + .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 12 +- + sound/arm/Kconfig | 7 + + sound/arm/Makefile | 5 + + sound/arm/bcm2835-ctl.c | 323 ++++++++ + sound/arm/bcm2835-pcm.c | 547 +++++++++++++ + sound/arm/bcm2835-vchiq.c | 902 +++++++++++++++++++++ + sound/arm/bcm2835.c | 420 ++++++++++ + sound/arm/bcm2835.h | 167 ++++ + sound/arm/vc_vchi_audioserv_defs.h | 116 +++ + 13 files changed, 2593 insertions(+), 7 deletions(-) create mode 100755 sound/arm/bcm2835-ctl.c create mode 100755 sound/arm/bcm2835-pcm.c create mode 100755 sound/arm/bcm2835-vchiq.c @@ -83479,7 +84384,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 752ae6e..d60513f 100644 +index 632023a..ab06b52 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 = { @@ -83550,6 +84455,76 @@ index 752ae6e..d60513f 100644 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; +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 5a4182e..25e7011 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 +@@ -288,11 +288,12 @@ VCHIQ_STATUS_T vchiq_open_service( + NULL); + + if (service) { ++ *phandle = service->handle; + status = vchiq_open_service_internal(service, current->pid); +- if (status == VCHIQ_SUCCESS) +- *phandle = service->handle; +- else ++ if (status != VCHIQ_SUCCESS) { + vchiq_remove_service(service->handle); ++ *phandle = VCHIQ_SERVICE_HANDLE_INVALID; ++ } + } + + failed: +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c +index a0b069d..bc27bea 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c +@@ -636,6 +636,9 @@ int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, + { + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; + SHIM_SERVICE_T *service = service_alloc(instance, setup); ++ ++ *handle = (VCHI_SERVICE_HANDLE_T)service; ++ + if (service) { + VCHIQ_SERVICE_PARAMS_T params; + VCHIQ_STATUS_T status; +@@ -652,11 +655,10 @@ int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, + if (status != VCHIQ_SUCCESS) { + service_free(service); + service = NULL; ++ *handle = NULL; + } + } + +- *handle = (VCHI_SERVICE_HANDLE_T)service; +- + return (service != NULL) ? 0 : -1; + } + EXPORT_SYMBOL(vchi_service_open); +@@ -667,6 +669,9 @@ int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle, + { + VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; + SHIM_SERVICE_T *service = service_alloc(instance, setup); ++ ++ *handle = (VCHI_SERVICE_HANDLE_T)service; ++ + if (service) { + VCHIQ_SERVICE_PARAMS_T params; + VCHIQ_STATUS_T status; +@@ -682,11 +687,10 @@ int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle, + if (status != VCHIQ_SUCCESS) { + service_free(service); + service = NULL; ++ *handle = NULL; + } + } + +- *handle = (VCHI_SERVICE_HANDLE_T)service; +- + return (service != NULL) ? 0 : -1; + } + EXPORT_SYMBOL(vchi_service_create); diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 885683a..f7ceafd 100644 --- a/sound/arm/Kconfig @@ -83582,10 +84557,10 @@ index 8c0c851..6796d7f 100644 +ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000 diff --git a/sound/arm/bcm2835-ctl.c b/sound/arm/bcm2835-ctl.c new file mode 100755 -index 0000000..8c5334a +index 0000000..aad905f --- /dev/null +++ b/sound/arm/bcm2835-ctl.c -@@ -0,0 +1,200 @@ +@@ -0,0 +1,323 @@ +/***************************************************************************** +* Copyright 2011 Broadcom Corporation. All rights reserved. +* @@ -83618,6 +84593,7 @@ index 0000000..8c5334a +#include +#include +#include ++#include + +#include "bcm2835.h" + @@ -83771,6 +84747,122 @@ index 0000000..8c5334a + }, +}; + ++static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ ++static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ ucontrol->value.iec958.status[i] = ++ (chip->spdif_status >> (i * 8)) && 0xff; ++ ++ return 0; ++} ++ ++static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); ++ unsigned int val = 0; ++ int i, change; ++ ++ for (i = 0; i < 4; i++) ++ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); ++ ++ change = val != chip->spdif_status; ++ chip->spdif_status = val; ++ ++ return change; ++} ++ ++static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ ++static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ /* bcm2835 supports only consumer mode and sets all other format flags ++ * automatically. So the only thing left is signalling non-audio ++ * content */ ++ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO; ++ return 0; ++} ++ ++static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ ++static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ ucontrol->value.iec958.status[i] = ++ (chip->spdif_status >> (i * 8)) & 0xff; ++ return 0; ++} ++ ++static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); ++ unsigned int val = 0; ++ int i, change; ++ ++ for (i = 0; i < 4; i++) ++ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); ++ change = val != chip->spdif_status; ++ chip->spdif_status = val; ++ ++ return change; ++} ++ ++static struct snd_kcontrol_new snd_bcm2835_spdif[] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), ++ .info = snd_bcm2835_spdif_default_info, ++ .get = snd_bcm2835_spdif_default_get, ++ .put = snd_bcm2835_spdif_default_put ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ, ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), ++ .info = snd_bcm2835_spdif_mask_info, ++ .get = snd_bcm2835_spdif_mask_get, ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | ++ SNDRV_CTL_ELEM_ACCESS_INACTIVE, ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), ++ .info = snd_bcm2835_spdif_stream_info, ++ .get = snd_bcm2835_spdif_stream_get, ++ .put = snd_bcm2835_spdif_stream_put, ++ }, ++}; ++ +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip) +{ + int err; @@ -83784,14 +84876,20 @@ index 0000000..8c5334a + if (err < 0) + return err; + } ++ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) { ++ err = snd_ctl_add(chip->card, ++ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip)); ++ if (err < 0) ++ return err; ++ } + return 0; +} diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c new file mode 100755 -index 0000000..2e7d405 +index 0000000..0929e00 --- /dev/null +++ b/sound/arm/bcm2835-pcm.c -@@ -0,0 +1,409 @@ +@@ -0,0 +1,547 @@ +/***************************************************************************** +* Copyright 2011 Broadcom Corporation. All rights reserved. +* @@ -83809,11 +84907,14 @@ index 0000000..2e7d405 +#include +#include + ++#include ++ +#include "bcm2835.h" + +/* hardware definition */ +static struct snd_pcm_hardware snd_bcm2835_playback_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER), ++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | ++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, @@ -83827,6 +84928,23 @@ index 0000000..2e7d405 + .periods_max = 128, +}; + ++static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | ++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000, ++ .rate_min = 44100, ++ .rate_max = 48000, ++ .channels_min = 2, ++ .channels_max = 2, ++ .buffer_bytes_max = 128 * 1024, ++ .period_bytes_min = 1 * 1024, ++ .period_bytes_max = 128 * 1024, ++ .periods_min = 1, ++ .periods_max = 128, ++}; ++ +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime) +{ + audio_info("Freeing up alsa stream here ..\n"); @@ -83882,7 +85000,8 @@ index 0000000..2e7d405 +} + +/* open callback */ -+static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) ++static int snd_bcm2835_playback_open_generic( ++ struct snd_pcm_substream *substream, int spdif) +{ + bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; @@ -83892,9 +85011,19 @@ index 0000000..2e7d405 + + audio_info(" .. IN (%d)\n", substream->number); + ++ if(mutex_lock_interruptible(&chip->audio_mutex)) ++ { ++ audio_error("Interrupted whilst waiting for lock\n"); ++ return -EINTR; ++ } + audio_info("Alsa open (%d)\n", substream->number); + idx = substream->number; + ++ if (spdif && chip->opened != 0) ++ return -EBUSY; ++ else if (!spdif && (chip->opened & (1 << idx))) ++ return -EBUSY; ++ + if (idx > MAX_SUBSTREAMS) { + audio_error + ("substream(%d) device doesn't exist max(%d) substreams allowed\n", @@ -83913,7 +85042,8 @@ index 0000000..2e7d405 + + alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL); + if (alsa_stream == NULL) { -+ return -ENOMEM; ++ err = -ENOMEM; ++ goto out; + } + + /* Initialise alsa_stream */ @@ -83936,31 +85066,56 @@ index 0000000..2e7d405 + } + runtime->private_data = alsa_stream; + runtime->private_free = snd_bcm2835_playback_free; -+ runtime->hw = snd_bcm2835_playback_hw; ++ if (spdif) { ++ runtime->hw = snd_bcm2835_playback_spdif_hw; ++ } else { ++ /* clear spdif status, as we are not in spdif mode */ ++ chip->spdif_status = 0; ++ runtime->hw = snd_bcm2835_playback_hw; ++ } + /* minimum 16 bytes alignment (for vchiq bulk transfers) */ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + 16); + + chip->alsa_stream[idx] = alsa_stream; + ++ chip->opened |= (1 << idx); + alsa_stream->open = 1; + alsa_stream->draining = 1; + +out: ++ mutex_unlock(&chip->audio_mutex); ++ + audio_info(" .. OUT =%d\n", err); + + return err; +} + ++static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) ++{ ++ return snd_bcm2835_playback_open_generic(substream, 0); ++} ++ ++static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream) ++{ ++ return snd_bcm2835_playback_open_generic(substream, 1); ++} ++ +/* close callback */ +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) +{ + /* the hardware-specific codes will be here */ + ++ audio_info(" .. IN\n"); ++ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); ++ if(mutex_lock_interruptible(&chip->audio_mutex)) ++ { ++ audio_error("Interrupted whilst waiting for lock\n"); ++ return -EINTR; ++ } + struct snd_pcm_runtime *runtime = substream->runtime; + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; + -+ audio_info(" .. IN\n"); + audio_info("Alsa close\n"); + + /* @@ -83989,6 +85144,9 @@ index 0000000..2e7d405 + * runtime->private_free callback we registered in *_open above + */ + ++ chip->opened &= ~(1 << substream->number); ++ ++ mutex_unlock(&chip->audio_mutex); + audio_info(" .. OUT\n"); + + return 0; @@ -83998,10 +85156,9 @@ index 0000000..2e7d405 +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ -+ int err; + struct snd_pcm_runtime *runtime = substream->runtime; -+ bcm2835_alsa_stream_t *alsa_stream = -+ (bcm2835_alsa_stream_t *) runtime->private_data; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ int err; + + audio_info(" .. IN\n"); + @@ -84012,19 +85169,9 @@ index 0000000..2e7d405 + return err; + } + -+ err = bcm2835_audio_set_params(alsa_stream, params_channels(params), -+ params_rate(params), -+ snd_pcm_format_width(params_format -+ (params))); -+ if (err < 0) { -+ audio_error(" error setting hw params\n"); -+ } -+ -+ bcm2835_audio_setup(alsa_stream); -+ -+ /* in preparation of the stream, set the controls (volume level) of the stream */ -+ bcm2835_audio_set_ctls(alsa_stream->chip); -+ ++ alsa_stream->channels = params_channels(params); ++ alsa_stream->params_rate = params_rate(params); ++ alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params)); + audio_info(" .. OUT\n"); + + return err; @@ -84040,11 +85187,41 @@ index 0000000..2e7d405 +/* prepare callback */ +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) +{ ++ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ int channels; ++ int err; + + audio_info(" .. IN\n"); + ++ /* notify the vchiq that it should enter spdif passthrough mode by ++ * setting channels=0 (see ++ * https://github.com/raspberrypi/linux/issues/528) */ ++ if (chip->spdif_status & IEC958_AES0_NONAUDIO) ++ channels = 0; ++ else ++ channels = alsa_stream->channels; ++ ++ err = bcm2835_audio_set_params(alsa_stream, channels, ++ alsa_stream->params_rate, ++ alsa_stream->pcm_format_width); ++ if (err < 0) { ++ audio_error(" error setting hw params\n"); ++ } ++ ++ bcm2835_audio_setup(alsa_stream); ++ ++ /* in preparation of the stream, set the controls (volume level) of the stream */ ++ bcm2835_audio_set_ctls(alsa_stream->chip); ++ ++ ++ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); ++ ++ alsa_stream->pcm_indirect.hw_buffer_size = ++ alsa_stream->pcm_indirect.sw_buffer_size = ++ snd_pcm_lib_buffer_bytes(substream); ++ + alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); + alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); + alsa_stream->pos = 0; @@ -84057,6 +85234,32 @@ index 0000000..2e7d405 + return 0; +} + ++static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream, ++ struct snd_pcm_indirect *rec, size_t bytes) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ void *src = (void *)(substream->runtime->dma_area + rec->sw_data); ++ int err; ++ ++ err = bcm2835_audio_write(alsa_stream, bytes, src); ++ if (err) ++ audio_error(" Failed to transfer to alsa device (%d)\n", err); ++ ++} ++ ++static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect; ++ ++ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max; ++ snd_pcm_indirect_playback_transfer(substream, pcm_indirect, ++ snd_bcm2835_pcm_transfer); ++ return 0; ++} ++ +/* trigger callback */ +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ @@ -84073,6 +85276,11 @@ index 0000000..2e7d405 + if (!alsa_stream->running) { + err = bcm2835_audio_start(alsa_stream); + if (err == 0) { ++ alsa_stream->pcm_indirect.hw_io = ++ alsa_stream->pcm_indirect.hw_data = ++ bytes_to_frames(runtime, ++ alsa_stream->pos); ++ substream->ops->ack(substream); + alsa_stream->running = 1; + alsa_stream->draining = 1; + } else { @@ -84121,30 +85329,9 @@ index 0000000..2e7d405 + alsa_stream->pos); + + audio_info(" .. OUT\n"); -+ return bytes_to_frames(runtime, alsa_stream->pos); -+} -+ -+static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream, -+ int channel, snd_pcm_uframes_t pos, void *src, -+ snd_pcm_uframes_t count) -+{ -+ int ret; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ -+ audio_info(" .. IN\n"); -+ audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n", -+ frames_to_bytes(runtime, count), frames_to_bytes(runtime, -+ runtime-> -+ status-> -+ hw_ptr), -+ frames_to_bytes(runtime, runtime->control->appl_ptr), -+ alsa_stream->pos); -+ ret = -+ bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count), -+ src); -+ audio_info(" .. OUT\n"); -+ return ret; ++ return snd_pcm_indirect_playback_pointer(substream, ++ &alsa_stream->pcm_indirect, ++ alsa_stream->pos); +} + +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, @@ -84166,7 +85353,19 @@ index 0000000..2e7d405 + .prepare = snd_bcm2835_pcm_prepare, + .trigger = snd_bcm2835_pcm_trigger, + .pointer = snd_bcm2835_pcm_pointer, -+ .copy = snd_bcm2835_pcm_copy, ++ .ack = snd_bcm2835_pcm_ack, ++}; ++ ++static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { ++ .open = snd_bcm2835_playback_spdif_open, ++ .close = snd_bcm2835_playback_close, ++ .ioctl = snd_bcm2835_pcm_lib_ioctl, ++ .hw_params = snd_bcm2835_pcm_hw_params, ++ .hw_free = snd_bcm2835_pcm_hw_free, ++ .prepare = snd_bcm2835_pcm_prepare, ++ .trigger = snd_bcm2835_pcm_trigger, ++ .pointer = snd_bcm2835_pcm_pointer, ++ .ack = snd_bcm2835_pcm_ack, +}; + +/* create a pcm device */ @@ -84176,6 +85375,12 @@ index 0000000..2e7d405 + int err; + + audio_info(" .. IN\n"); ++ mutex_init(&chip->audio_mutex); ++ if(mutex_lock_interruptible(&chip->audio_mutex)) ++ { ++ audio_error("Interrupted whilst waiting for lock\n"); ++ return -EINTR; ++ } + err = + snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm); + if (err < 0) @@ -84197,16 +85402,47 @@ index 0000000..2e7d405 + (GFP_KERNEL), 64 * 1024, + 64 * 1024); + ++ mutex_unlock(&chip->audio_mutex); ++ audio_info(" .. OUT\n"); ++ ++ return 0; ++} ++ ++int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip) ++{ ++ struct snd_pcm *pcm; ++ int err; ++ ++ audio_info(" .. IN\n"); ++ if(mutex_lock_interruptible(&chip->audio_mutex)) ++ { ++ audio_error("Interrupted whilst waiting for lock\n"); ++ return -EINTR; ++ } ++ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm); ++ if (err < 0) ++ return err; ++ ++ pcm->private_data = chip; ++ strcpy(pcm->name, "bcm2835 IEC958/HDMI"); ++ chip->pcm_spdif = pcm; ++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ++ &snd_bcm2835_playback_spdif_ops); ++ ++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, ++ snd_dma_continuous_data (GFP_KERNEL), ++ 64 * 1024, 64 * 1024); ++ mutex_unlock(&chip->audio_mutex); + audio_info(" .. OUT\n"); + + return 0; +} diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c new file mode 100755 -index 0000000..b9b4fe8 +index 0000000..cfa669e --- /dev/null +++ b/sound/arm/bcm2835-vchiq.c -@@ -0,0 +1,844 @@ +@@ -0,0 +1,902 @@ +/***************************************************************************** +* Copyright 2011 Broadcom Corporation. All rights reserved. +* @@ -84236,6 +85472,7 @@ index 0000000..b9b4fe8 +#include +#include +#include ++#include + +#include "bcm2835.h" + @@ -84246,6 +85483,10 @@ index 0000000..b9b4fe8 + +/* ---- Private Constants and Types ------------------------------------------ */ + ++#define BCM2835_AUDIO_STOP 0 ++#define BCM2835_AUDIO_START 1 ++#define BCM2835_AUDIO_WRITE 2 ++ +/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */ +#ifdef AUDIO_DEBUG_ENABLE + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg) @@ -84262,7 +85503,7 @@ index 0000000..b9b4fe8 +typedef struct opaque_AUDIO_INSTANCE_T { + uint32_t num_connections; + VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS]; -+ struct semaphore msg_avail_event; ++ struct completion msg_avail_comp; + struct mutex vchi_mutex; + bcm2835_alsa_stream_t *alsa_stream; + int32_t result; @@ -84279,27 +85520,35 @@ index 0000000..b9b4fe8 + +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream); +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream); ++static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream, ++ uint32_t count, void *src); + +typedef struct { + struct work_struct my_work; + bcm2835_alsa_stream_t *alsa_stream; -+ int x; ++ int cmd; ++ void *src; ++ uint32_t count; +} my_work_t; + +static void my_wq_function(struct work_struct *work) +{ + my_work_t *w = (my_work_t *) work; + int ret = -9; -+ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x); -+ switch (w->x) { -+ case 1: ++ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd); ++ switch (w->cmd) { ++ case BCM2835_AUDIO_START: + ret = bcm2835_audio_start_worker(w->alsa_stream); + break; -+ case 2: ++ case BCM2835_AUDIO_STOP: + ret = bcm2835_audio_stop_worker(w->alsa_stream); + break; ++ case BCM2835_AUDIO_WRITE: ++ ret = bcm2835_audio_write_worker(w->alsa_stream, w->count, ++ w->src); ++ break; + default: -+ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x); ++ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd); + break; + } + kfree((void *)work); @@ -84316,7 +85565,7 @@ index 0000000..b9b4fe8 + if (work) { + INIT_WORK((struct work_struct *)work, my_wq_function); + work->alsa_stream = alsa_stream; -+ work->x = 1; ++ work->cmd = BCM2835_AUDIO_START; + if (queue_work + (alsa_stream->my_wq, (struct work_struct *)work)) + ret = 0; @@ -84337,7 +85586,31 @@ index 0000000..b9b4fe8 + if (work) { + INIT_WORK((struct work_struct *)work, my_wq_function); + work->alsa_stream = alsa_stream; -+ work->x = 2; ++ work->cmd = BCM2835_AUDIO_STOP; ++ if (queue_work ++ (alsa_stream->my_wq, (struct work_struct *)work)) ++ ret = 0; ++ } else ++ LOG_ERR(" .. Error: NULL work kmalloc\n"); ++ } ++ LOG_DBG(" .. OUT %d\n", ret); ++ return ret; ++} ++ ++int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream, ++ uint32_t count, void *src) ++{ ++ int ret = -1; ++ LOG_DBG(" .. IN\n"); ++ if (alsa_stream->my_wq) { ++ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC); ++ /*--- Queue some work (item 1) ---*/ ++ if (work) { ++ INIT_WORK((struct work_struct *)work, my_wq_function); ++ work->alsa_stream = alsa_stream; ++ work->cmd = BCM2835_AUDIO_WRITE; ++ work->src = src; ++ work->count = count; + if (queue_work + (alsa_stream->my_wq, (struct work_struct *)work)) + ret = 0; @@ -84372,14 +85645,22 @@ index 0000000..b9b4fe8 + int32_t status; + int32_t msg_len; + VC_AUDIO_MSG_T m; -+ bcm2835_alsa_stream_t *alsa_stream = 0; -+ LOG_DBG(" .. IN instance=%p, param=%p, reason=%d, handle=%p\n", -+ instance, param, reason, msg_handle); ++ LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n", ++ instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle); + -+ if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) { ++ if (reason != VCHI_CALLBACK_MSG_AVAILABLE) { + return; + } -+ alsa_stream = instance->alsa_stream; ++ if (!instance) { ++ LOG_ERR(" .. instance is null\n"); ++ BUG(); ++ return; ++ } ++ if (!instance->vchi_handle[0]) { ++ LOG_ERR(" .. instance->vchi_handle[0] is null\n"); ++ BUG(); ++ return; ++ } + status = vchi_msg_dequeue(instance->vchi_handle[0], + &m, sizeof m, &msg_len, VCHI_FLAGS_NONE); + if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { @@ -84387,8 +85668,9 @@ index 0000000..b9b4fe8 + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n", + instance, m.u.result.success); + instance->result = m.u.result.success; -+ up(&instance->msg_avail_event); ++ complete(&instance->msg_avail_comp); + } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { ++ bcm2835_alsa_stream_t *alsa_stream = instance->alsa_stream; + irq_handler_t callback = (irq_handler_t) m.u.complete.callback; + LOG_DBG + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n", @@ -84397,11 +85679,11 @@ index 0000000..b9b4fe8 + atomic_add(m.u.complete.count, &alsa_stream->retrieved); + callback(0, alsa_stream); + } else { -+ LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n", ++ LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n", + alsa_stream, callback); + } + } else { -+ LOG_DBG(" .. unexpected m.type=%d\n", m.type); ++ LOG_ERR(" .. unexpected m.type=%d\n", m.type); + } + LOG_DBG(" .. OUT\n"); +} @@ -84425,6 +85707,8 @@ index 0000000..b9b4fe8 + } + /* Allocate memory for this instance */ + instance = kmalloc(sizeof(*instance), GFP_KERNEL); ++ if (!instance) ++ return NULL; + + memset(instance, 0, sizeof(*instance)); + instance->num_connections = num_connections; @@ -84446,8 +85730,10 @@ index 0000000..b9b4fe8 + 0 // want crc check on bulk transfers + }; + ++ LOG_DBG("%s: about to open %i\n", __func__, i); + status = vchi_service_open(vchi_instance, ¶ms, + &instance->vchi_handle[i]); ++ LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status); + if (status) { + LOG_ERR + ("%s: failed to open VCHI service connection (status=%d)\n", @@ -84459,14 +85745,18 @@ index 0000000..b9b4fe8 + vchi_service_release(instance->vchi_handle[i]); + } + ++ LOG_DBG("%s: okay\n", __func__); + return instance; + +err_close_services: + for (i = 0; i < instance->num_connections; i++) { -+ vchi_service_close(instance->vchi_handle[i]); ++ LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]); ++ if (instance->vchi_handle[i]) ++ vchi_service_close(instance->vchi_handle[i]); + } + + kfree(instance); ++ LOG_ERR("%s: error\n", __func__); + + return NULL; +} @@ -84517,12 +85807,13 @@ index 0000000..b9b4fe8 +{ + static VCHI_INSTANCE_T vchi_instance; + static VCHI_CONNECTION_T *vchi_connection; ++ static int initted; + AUDIO_INSTANCE_T *instance = alsa_stream->instance; + int ret; + LOG_DBG(" .. IN\n"); + -+ LOG_INFO("%s: start", __func__); -+ //BUG_ON(instance); ++ LOG_INFO("%s: start\n", __func__); ++ BUG_ON(instance); + if (instance) { + LOG_ERR("%s: VCHI instance already open (%p)\n", + __func__, instance); @@ -84533,27 +85824,30 @@ index 0000000..b9b4fe8 + } + + /* Initialize and create a VCHI connection */ -+ ret = vchi_initialise(&vchi_instance); -+ if (ret != 0) { -+ LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n", -+ __func__, ret); ++ if (!initted) { ++ ret = vchi_initialise(&vchi_instance); ++ if (ret != 0) { ++ LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n", ++ __func__, ret); + -+ ret = -EIO; -+ goto err_free_mem; -+ } -+ ret = vchi_connect(NULL, 0, vchi_instance); -+ if (ret != 0) { -+ LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n", -+ __func__, ret); ++ ret = -EIO; ++ goto err_free_mem; ++ } ++ ret = vchi_connect(NULL, 0, vchi_instance); ++ if (ret != 0) { ++ LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n", ++ __func__, ret); + -+ ret = -EIO; -+ goto err_free_mem; ++ ret = -EIO; ++ goto err_free_mem; ++ } ++ initted = 1; + } + + /* Initialize an instance of the audio service */ + instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1); + -+ if (instance == NULL /*|| audio_handle != instance */ ) { ++ if (instance == NULL) { + LOG_ERR("%s: failed to initialize audio service\n", __func__); + + ret = -EPERM; @@ -84586,6 +85880,7 @@ index 0000000..b9b4fe8 + goto exit; + } + instance = alsa_stream->instance; ++ LOG_DBG(" instance (%p)\n", instance); + + if(mutex_lock_interruptible(&instance->vchi_mutex)) + { @@ -84644,8 +85939,8 @@ index 0000000..b9b4fe8 + m.u.control.dest = chip->dest; + m.u.control.volume = chip->volume; + -+ /* Create the message available event */ -+ sema_init(&instance->msg_avail_event, 0); ++ /* Create the message available completion */ ++ init_completion(&instance->msg_avail_comp); + + /* Send the message to the videocore */ + success = vchi_msg_queue(instance->vchi_handle[0], @@ -84661,11 +85956,10 @@ index 0000000..b9b4fe8 + } + + /* We are expecting a reply from the videocore */ -+ if (down_interruptible(&instance->msg_avail_event)) { ++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); ++ if (ret) { + LOG_ERR("%s: failed on waiting for event (status=%d)\n", + __func__, success); -+ -+ ret = -1; + goto unlock; + } + @@ -84691,6 +85985,7 @@ index 0000000..b9b4fe8 + int i; + int ret = 0; + LOG_DBG(" .. IN\n"); ++ LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume); + + /* change ctls for all substreams */ + for (i = 0; i < MAX_SUBSTREAMS; i++) { @@ -84703,10 +85998,10 @@ index 0000000..b9b4fe8 + else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */ + (chip->alsa_stream[i], chip) != 0) + { -+ LOG_DBG("Couldn't set the controls for stream %d\n", i); ++ LOG_ERR("Couldn't set the controls for stream %d\n", i); + ret = -1; + } -+ else LOG_DBG(" Controls set for stream %d\n", i); ++ else LOG_ERR(" Controls set for stream %d\n", i); + } + } + LOG_DBG(" .. OUT ret=%d\n", ret); @@ -84748,8 +86043,8 @@ index 0000000..b9b4fe8 + m.u.config.samplerate = samplerate; + m.u.config.bps = bps; + -+ /* Create the message available event */ -+ sema_init(&instance->msg_avail_event, 0); ++ /* Create the message available completion */ ++ init_completion(&instance->msg_avail_comp); + + /* Send the message to the videocore */ + success = vchi_msg_queue(instance->vchi_handle[0], @@ -84765,11 +86060,10 @@ index 0000000..b9b4fe8 + } + + /* We are expecting a reply from the videocore */ -+ if (down_interruptible(&instance->msg_avail_event)) { ++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); ++ if (ret) { + LOG_ERR("%s: failed on waiting for event (status=%d)\n", + __func__, success); -+ -+ ret = -1; + goto unlock; + } + @@ -84822,7 +86116,7 @@ index 0000000..b9b4fe8 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (success != 0) { -+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", + __func__, success); + + ret = -1; @@ -84862,7 +86156,7 @@ index 0000000..b9b4fe8 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (success != 0) { -+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", + __func__, success); + + ret = -1; @@ -84897,8 +86191,8 @@ index 0000000..b9b4fe8 + + m.type = VC_AUDIO_MSG_TYPE_CLOSE; + -+ /* Create the message available event */ -+ sema_init(&instance->msg_avail_event, 0); ++ /* Create the message available completion */ ++ init_completion(&instance->msg_avail_comp); + + /* Send the message to the videocore */ + success = vchi_msg_queue(instance->vchi_handle[0], @@ -84906,20 +86200,20 @@ index 0000000..b9b4fe8 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (success != 0) { -+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", + __func__, success); + ret = -1; + goto unlock; + } -+ if (down_interruptible(&instance->msg_avail_event)) { -+ LOG_ERR("%s: failed on waiting for event (status=%d)", -+ __func__, success); + -+ ret = -1; ++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); ++ if (ret) { ++ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ __func__, success); + goto unlock; + } + if (instance->result != 0) { -+ LOG_ERR("%s: failed result (status=%d)", ++ LOG_ERR("%s: failed result (status=%d)\n", + __func__, instance->result); + + ret = -1; @@ -84941,8 +86235,8 @@ index 0000000..b9b4fe8 + return ret; +} + -+int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count, -+ void *src) ++int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream, ++ uint32_t count, void *src) +{ + VC_AUDIO_MSG_T m; + AUDIO_INSTANCE_T *instance = alsa_stream->instance; @@ -84977,7 +86271,7 @@ index 0000000..b9b4fe8 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + + if (success != 0) { -+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", + __func__, success); + + ret = -1; @@ -85006,7 +86300,7 @@ index 0000000..b9b4fe8 + } + if (success != 0) { + LOG_ERR -+ ("%s: failed on vchi_bulk_queue_transmit (status=%d)", ++ ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n", + __func__, success); + + ret = -1; @@ -85053,10 +86347,10 @@ index 0000000..b9b4fe8 +MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio"); diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c new file mode 100755 -index 0000000..317e7d9 +index 0000000..7ed5079 --- /dev/null +++ b/sound/arm/bcm2835.c -@@ -0,0 +1,413 @@ +@@ -0,0 +1,420 @@ +/***************************************************************************** +* Copyright 2011 Broadcom Corporation. All rights reserved. +* @@ -85158,31 +86452,37 @@ index 0000000..317e7d9 + if (dev > 0) + goto add_register_map; + -+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card); ++ err = snd_card_new(NULL, index[dev], id[dev], THIS_MODULE, 0, &g_card); + if (err < 0) + goto out; + + snd_card_set_dev(g_card, &pdev->dev); -+ strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver"); ++ strcpy(g_card->driver, "bcm2835"); + strcpy(g_card->shortname, "bcm2835 ALSA"); + sprintf(g_card->longname, "%s", g_card->shortname); + + err = snd_bcm2835_create(g_card, pdev, &chip); + if (err < 0) { -+ printk(KERN_ERR "Failed to create bcm2835 chip\n"); ++ dev_err(&pdev->dev, "Failed to create bcm2835 chip\n"); + goto out_bcm2835_create; + } + + g_chip = chip; + err = snd_bcm2835_new_pcm(chip); + if (err < 0) { -+ printk(KERN_ERR "Failed to create new BCM2835 pcm device\n"); ++ dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n"); + goto out_bcm2835_new_pcm; + } + ++ err = snd_bcm2835_new_spdif_pcm(chip); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n"); ++ goto out_bcm2835_new_spdif; ++ } ++ + err = snd_bcm2835_new_ctl(chip); + if (err < 0) { -+ printk(KERN_ERR "Failed to create new BCM2835 ctl\n"); ++ dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n"); + goto out_bcm2835_new_ctl; + } + @@ -85198,14 +86498,14 @@ index 0000000..317e7d9 + if (dev == 0) { + err = snd_card_register(card); + if (err < 0) { -+ printk(KERN_ERR -+ "Failed to register bcm2835 ALSA card \n"); ++ dev_err(&pdev->dev, ++ "Failed to register bcm2835 ALSA card \n"); + goto out_card_register; + } + platform_set_drvdata(pdev, card); -+ printk(KERN_INFO "bcm2835 ALSA card created!\n"); ++ audio_info("bcm2835 ALSA card created!\n"); + } else { -+ printk(KERN_INFO "bcm2835 ALSA chip created!\n"); ++ audio_info("bcm2835 ALSA chip created!\n"); + platform_set_drvdata(pdev, (void *)dev); + } + @@ -85215,15 +86515,16 @@ index 0000000..317e7d9 + +out_card_register: +out_bcm2835_new_ctl: ++out_bcm2835_new_spdif: +out_bcm2835_new_pcm: +out_bcm2835_create: + BUG_ON(!g_card); + if (snd_card_free(g_card)) -+ printk(KERN_ERR "Failed to free Registered alsa card\n"); ++ dev_err(&pdev->dev, "Failed to free Registered alsa card\n"); + g_card = NULL; +out: + dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */ -+ printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n"); ++ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n"); + return err; +} + @@ -85385,49 +86686,49 @@ index 0000000..317e7d9 + int err; + err = platform_driver_register(&bcm2835_alsa0_driver); + if (err) { -+ printk("Error registering bcm2835_alsa0_driver %d .\n", err); ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); + goto out; + } + + err = platform_driver_register(&bcm2835_alsa1_driver); + if (err) { -+ printk("Error registering bcm2835_alsa1_driver %d .\n", err); ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); + goto unregister_0; + } + + err = platform_driver_register(&bcm2835_alsa2_driver); + if (err) { -+ printk("Error registering bcm2835_alsa2_driver %d .\n", err); ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); + goto unregister_1; + } + + err = platform_driver_register(&bcm2835_alsa3_driver); + if (err) { -+ printk("Error registering bcm2835_alsa3_driver %d .\n", err); ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); + goto unregister_2; + } + + err = platform_driver_register(&bcm2835_alsa4_driver); + if (err) { -+ printk("Error registering bcm2835_alsa4_driver %d .\n", err); ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); + goto unregister_3; + } + + err = platform_driver_register(&bcm2835_alsa5_driver); + if (err) { -+ printk("Error registering bcm2835_alsa5_driver %d .\n", err); ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); + goto unregister_4; + } + + err = platform_driver_register(&bcm2835_alsa6_driver); + if (err) { -+ printk("Error registering bcm2835_alsa6_driver %d .\n", err); ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); + goto unregister_5; + } + + err = platform_driver_register(&bcm2835_alsa7_driver); + if (err) { -+ printk("Error registering bcm2835_alsa7_driver %d .\n", err); ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); + goto unregister_6; + } + @@ -85472,10 +86773,10 @@ index 0000000..317e7d9 +MODULE_ALIAS("platform:bcm2835_alsa"); diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h new file mode 100755 -index 0000000..080bd5c +index 0000000..0f71c5d --- /dev/null +++ b/sound/arm/bcm2835.h -@@ -0,0 +1,155 @@ +@@ -0,0 +1,167 @@ +/***************************************************************************** +* Copyright 2011 Broadcom Corporation. All rights reserved. +* @@ -85501,6 +86802,7 @@ index 0000000..080bd5c +#include +#include +#include ++#include +#include + +/* @@ -85574,6 +86876,7 @@ index 0000000..080bd5c +typedef struct bcm2835_chip { + struct snd_card *card; + struct snd_pcm *pcm; ++ struct snd_pcm *pcm_spdif; + /* Bitmat for valid reg_base and irq numbers */ + uint32_t avail_substreams; + struct platform_device *pdev[MAX_SUBSTREAMS]; @@ -85583,11 +86886,16 @@ index 0000000..080bd5c + int old_volume; /* stores the volume value whist muted */ + int dest; + int mute; ++ ++ unsigned int opened; ++ unsigned int spdif_status; ++ struct mutex audio_mutex; +} bcm2835_chip_t; + +typedef struct bcm2835_alsa_stream { + bcm2835_chip_t *chip; + struct snd_pcm_substream *substream; ++ struct snd_pcm_indirect pcm_indirect; + + struct semaphore buffers_update_sem; + struct semaphore control_sem; @@ -85599,6 +86907,10 @@ index 0000000..080bd5c + int running; + int draining; + ++ int channels; ++ int params_rate; ++ int pcm_format_width; ++ + unsigned int pos; + unsigned int buffer_size; + unsigned int period_size; @@ -85614,6 +86926,7 @@ index 0000000..080bd5c + +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip); +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip); ++int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip); + +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream); +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream); @@ -85757,493 +87070,10 @@ index 0000000..af3e6eb 2.0.3 -From 3f704f893f93fe39a09ab3bb24a00bd05f13428c Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 26 Apr 2013 10:08:31 -0700 -Subject: [PATCH 10/81] alsa: add mmap support and some cleanups to bcm2835 - ALSA driver - ---- - sound/arm/bcm2835-pcm.c | 69 ++++++++++++++++++++++-------------- - sound/arm/bcm2835-vchiq.c | 89 +++++++++++++++++++++++++++++++++-------------- - sound/arm/bcm2835.c | 34 +++++++++--------- - sound/arm/bcm2835.h | 2 ++ - 4 files changed, 124 insertions(+), 70 deletions(-) - -diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c -index 2e7d405..b4084bb 100755 ---- a/sound/arm/bcm2835-pcm.c -+++ b/sound/arm/bcm2835-pcm.c -@@ -19,7 +19,8 @@ - - /* hardware definition */ - static struct snd_pcm_hardware snd_bcm2835_playback_hw = { -- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER), -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | -+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, - .rate_min = 8000, -@@ -251,6 +252,12 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) - - audio_info(" .. IN\n"); - -+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); -+ -+ alsa_stream->pcm_indirect.hw_buffer_size = -+ alsa_stream->pcm_indirect.sw_buffer_size = -+ snd_pcm_lib_buffer_bytes(substream); -+ - alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); - alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); - alsa_stream->pos = 0; -@@ -263,6 +270,32 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) - return 0; - } - -+static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream, -+ struct snd_pcm_indirect *rec, size_t bytes) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ void *src = (void *)(substream->runtime->dma_area + rec->sw_data); -+ int err; -+ -+ err = bcm2835_audio_write(alsa_stream, bytes, src); -+ if (err) -+ audio_error(" Failed to transfer to alsa device (%d)\n", err); -+ -+} -+ -+static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect; -+ -+ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max; -+ snd_pcm_indirect_playback_transfer(substream, pcm_indirect, -+ snd_bcm2835_pcm_transfer); -+ return 0; -+} -+ - /* trigger callback */ - static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) - { -@@ -279,6 +312,11 @@ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) - if (!alsa_stream->running) { - err = bcm2835_audio_start(alsa_stream); - if (err == 0) { -+ alsa_stream->pcm_indirect.hw_io = -+ alsa_stream->pcm_indirect.hw_data = -+ bytes_to_frames(runtime, -+ alsa_stream->pos); -+ substream->ops->ack(substream); - alsa_stream->running = 1; - alsa_stream->draining = 1; - } else { -@@ -327,30 +365,9 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream) - alsa_stream->pos); - - audio_info(" .. OUT\n"); -- return bytes_to_frames(runtime, alsa_stream->pos); --} -- --static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream, -- int channel, snd_pcm_uframes_t pos, void *src, -- snd_pcm_uframes_t count) --{ -- int ret; -- struct snd_pcm_runtime *runtime = substream->runtime; -- bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -- -- audio_info(" .. IN\n"); -- audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n", -- frames_to_bytes(runtime, count), frames_to_bytes(runtime, -- runtime-> -- status-> -- hw_ptr), -- frames_to_bytes(runtime, runtime->control->appl_ptr), -- alsa_stream->pos); -- ret = -- bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count), -- src); -- audio_info(" .. OUT\n"); -- return ret; -+ return snd_pcm_indirect_playback_pointer(substream, -+ &alsa_stream->pcm_indirect, -+ alsa_stream->pos); - } - - static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, -@@ -372,7 +389,7 @@ static struct snd_pcm_ops snd_bcm2835_playback_ops = { - .prepare = snd_bcm2835_pcm_prepare, - .trigger = snd_bcm2835_pcm_trigger, - .pointer = snd_bcm2835_pcm_pointer, -- .copy = snd_bcm2835_pcm_copy, -+ .ack = snd_bcm2835_pcm_ack, - }; - - /* create a pcm device */ -diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c -index b9b4fe8..ee09b13 100755 ---- a/sound/arm/bcm2835-vchiq.c -+++ b/sound/arm/bcm2835-vchiq.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #include "bcm2835.h" - -@@ -37,6 +38,10 @@ - - /* ---- Private Constants and Types ------------------------------------------ */ - -+#define BCM2835_AUDIO_STOP 0 -+#define BCM2835_AUDIO_START 1 -+#define BCM2835_AUDIO_WRITE 2 -+ - /* Logging macros (for remapping to other logging mechanisms, i.e., printf) */ - #ifdef AUDIO_DEBUG_ENABLE - #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg) -@@ -53,7 +58,7 @@ - typedef struct opaque_AUDIO_INSTANCE_T { - uint32_t num_connections; - VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS]; -- struct semaphore msg_avail_event; -+ struct completion msg_avail_comp; - struct mutex vchi_mutex; - bcm2835_alsa_stream_t *alsa_stream; - int32_t result; -@@ -70,27 +75,35 @@ bool force_bulk = false; - - static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream); - static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream); -+static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream, -+ uint32_t count, void *src); - - typedef struct { - struct work_struct my_work; - bcm2835_alsa_stream_t *alsa_stream; -- int x; -+ int cmd; -+ void *src; -+ uint32_t count; - } my_work_t; - - static void my_wq_function(struct work_struct *work) - { - my_work_t *w = (my_work_t *) work; - int ret = -9; -- LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x); -- switch (w->x) { -- case 1: -+ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd); -+ switch (w->cmd) { -+ case BCM2835_AUDIO_START: - ret = bcm2835_audio_start_worker(w->alsa_stream); - break; -- case 2: -+ case BCM2835_AUDIO_STOP: - ret = bcm2835_audio_stop_worker(w->alsa_stream); - break; -+ case BCM2835_AUDIO_WRITE: -+ ret = bcm2835_audio_write_worker(w->alsa_stream, w->count, -+ w->src); -+ break; - default: -- LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x); -+ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd); - break; - } - kfree((void *)work); -@@ -107,7 +120,7 @@ int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream) - if (work) { - INIT_WORK((struct work_struct *)work, my_wq_function); - work->alsa_stream = alsa_stream; -- work->x = 1; -+ work->cmd = BCM2835_AUDIO_START; - if (queue_work - (alsa_stream->my_wq, (struct work_struct *)work)) - ret = 0; -@@ -128,7 +141,31 @@ int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream) - if (work) { - INIT_WORK((struct work_struct *)work, my_wq_function); - work->alsa_stream = alsa_stream; -- work->x = 2; -+ work->cmd = BCM2835_AUDIO_STOP; -+ if (queue_work -+ (alsa_stream->my_wq, (struct work_struct *)work)) -+ ret = 0; -+ } else -+ LOG_ERR(" .. Error: NULL work kmalloc\n"); -+ } -+ LOG_DBG(" .. OUT %d\n", ret); -+ return ret; -+} -+ -+int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream, -+ uint32_t count, void *src) -+{ -+ int ret = -1; -+ LOG_DBG(" .. IN\n"); -+ if (alsa_stream->my_wq) { -+ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC); -+ /*--- Queue some work (item 1) ---*/ -+ if (work) { -+ INIT_WORK((struct work_struct *)work, my_wq_function); -+ work->alsa_stream = alsa_stream; -+ work->cmd = BCM2835_AUDIO_WRITE; -+ work->src = src; -+ work->count = count; - if (queue_work - (alsa_stream->my_wq, (struct work_struct *)work)) - ret = 0; -@@ -178,7 +215,7 @@ static void audio_vchi_callback(void *param, - (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n", - instance, m.u.result.success); - instance->result = m.u.result.success; -- up(&instance->msg_avail_event); -+ complete(&instance->msg_avail_comp); - } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { - irq_handler_t callback = (irq_handler_t) m.u.complete.callback; - LOG_DBG -@@ -435,8 +472,8 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream, - m.u.control.dest = chip->dest; - m.u.control.volume = chip->volume; - -- /* Create the message available event */ -- sema_init(&instance->msg_avail_event, 0); -+ /* Create the message available completion */ -+ init_completion(&instance->msg_avail_comp); - - /* Send the message to the videocore */ - success = vchi_msg_queue(instance->vchi_handle[0], -@@ -452,11 +489,10 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream, - } - - /* We are expecting a reply from the videocore */ -- if (down_interruptible(&instance->msg_avail_event)) { -+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); -+ if (ret) { - LOG_ERR("%s: failed on waiting for event (status=%d)\n", - __func__, success); -- -- ret = -1; - goto unlock; - } - -@@ -539,8 +575,8 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream, - m.u.config.samplerate = samplerate; - m.u.config.bps = bps; - -- /* Create the message available event */ -- sema_init(&instance->msg_avail_event, 0); -+ /* Create the message available completion */ -+ init_completion(&instance->msg_avail_comp); - - /* Send the message to the videocore */ - success = vchi_msg_queue(instance->vchi_handle[0], -@@ -556,11 +592,10 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream, - } - - /* We are expecting a reply from the videocore */ -- if (down_interruptible(&instance->msg_avail_event)) { -+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); -+ if (ret) { - LOG_ERR("%s: failed on waiting for event (status=%d)\n", - __func__, success); -- -- ret = -1; - goto unlock; - } - -@@ -688,8 +723,8 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream) - - m.type = VC_AUDIO_MSG_TYPE_CLOSE; - -- /* Create the message available event */ -- sema_init(&instance->msg_avail_event, 0); -+ /* Create the message available completion */ -+ init_completion(&instance->msg_avail_comp); - - /* Send the message to the videocore */ - success = vchi_msg_queue(instance->vchi_handle[0], -@@ -702,11 +737,11 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream) - ret = -1; - goto unlock; - } -- if (down_interruptible(&instance->msg_avail_event)) { -+ -+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); -+ if (ret) { - LOG_ERR("%s: failed on waiting for event (status=%d)", - __func__, success); -- -- ret = -1; - goto unlock; - } - if (instance->result != 0) { -@@ -732,8 +767,8 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream) - return ret; - } - --int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count, -- void *src) -+int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream, -+ uint32_t count, void *src) - { - VC_AUDIO_MSG_T m; - AUDIO_INSTANCE_T *instance = alsa_stream->instance; -diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c -index 317e7d9..e2047a7 100755 ---- a/sound/arm/bcm2835.c -+++ b/sound/arm/bcm2835.c -@@ -110,20 +110,20 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - - err = snd_bcm2835_create(g_card, pdev, &chip); - if (err < 0) { -- printk(KERN_ERR "Failed to create bcm2835 chip\n"); -+ dev_err(&pdev->dev, "Failed to create bcm2835 chip\n"); - goto out_bcm2835_create; - } - - g_chip = chip; - err = snd_bcm2835_new_pcm(chip); - if (err < 0) { -- printk(KERN_ERR "Failed to create new BCM2835 pcm device\n"); -+ dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n"); - goto out_bcm2835_new_pcm; - } - - err = snd_bcm2835_new_ctl(chip); - if (err < 0) { -- printk(KERN_ERR "Failed to create new BCM2835 ctl\n"); -+ dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n"); - goto out_bcm2835_new_ctl; - } - -@@ -139,14 +139,14 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - if (dev == 0) { - err = snd_card_register(card); - if (err < 0) { -- printk(KERN_ERR -- "Failed to register bcm2835 ALSA card \n"); -+ dev_err(&pdev->dev, -+ "Failed to register bcm2835 ALSA card \n"); - goto out_card_register; - } - platform_set_drvdata(pdev, card); -- printk(KERN_INFO "bcm2835 ALSA card created!\n"); -+ audio_info("bcm2835 ALSA card created!\n"); - } else { -- printk(KERN_INFO "bcm2835 ALSA chip created!\n"); -+ audio_info("bcm2835 ALSA chip created!\n"); - platform_set_drvdata(pdev, (void *)dev); - } - -@@ -160,11 +160,11 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - out_bcm2835_create: - BUG_ON(!g_card); - if (snd_card_free(g_card)) -- printk(KERN_ERR "Failed to free Registered alsa card\n"); -+ dev_err(&pdev->dev, "Failed to free Registered alsa card\n"); - g_card = NULL; - out: - dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */ -- printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n"); -+ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n"); - return err; - } - -@@ -326,49 +326,49 @@ static int bcm2835_alsa_device_init(void) - int err; - err = platform_driver_register(&bcm2835_alsa0_driver); - if (err) { -- printk("Error registering bcm2835_alsa0_driver %d .\n", err); -+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); - goto out; - } - - err = platform_driver_register(&bcm2835_alsa1_driver); - if (err) { -- printk("Error registering bcm2835_alsa1_driver %d .\n", err); -+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); - goto unregister_0; - } - - err = platform_driver_register(&bcm2835_alsa2_driver); - if (err) { -- printk("Error registering bcm2835_alsa2_driver %d .\n", err); -+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); - goto unregister_1; - } - - err = platform_driver_register(&bcm2835_alsa3_driver); - if (err) { -- printk("Error registering bcm2835_alsa3_driver %d .\n", err); -+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); - goto unregister_2; - } - - err = platform_driver_register(&bcm2835_alsa4_driver); - if (err) { -- printk("Error registering bcm2835_alsa4_driver %d .\n", err); -+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); - goto unregister_3; - } - - err = platform_driver_register(&bcm2835_alsa5_driver); - if (err) { -- printk("Error registering bcm2835_alsa5_driver %d .\n", err); -+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); - goto unregister_4; - } - - err = platform_driver_register(&bcm2835_alsa6_driver); - if (err) { -- printk("Error registering bcm2835_alsa6_driver %d .\n", err); -+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); - goto unregister_5; - } - - err = platform_driver_register(&bcm2835_alsa7_driver); - if (err) { -- printk("Error registering bcm2835_alsa7_driver %d .\n", err); -+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); - goto unregister_6; - } - -diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h -index 080bd5c..36afee3 100755 ---- a/sound/arm/bcm2835.h -+++ b/sound/arm/bcm2835.h -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - #include - - /* -@@ -110,6 +111,7 @@ typedef struct bcm2835_chip { - typedef struct bcm2835_alsa_stream { - bcm2835_chip_t *chip; - struct snd_pcm_substream *substream; -+ struct snd_pcm_indirect pcm_indirect; - - struct semaphore buffers_update_sem; - struct semaphore control_sem; --- -2.0.3 - - -From c4bae551fcf8c2fd7f69aa23a79e165340199f20 Mon Sep 17 00:00:00 2001 +From bfb24ef6eda232bcbe30b9a87d8781169aead81a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 11/81] Add hwrng (hardware random number generator) driver +Subject: [PATCH 13/69] Add hwrng (hardware random number generator) driver --- arch/arm/mach-bcm2708/include/mach/platform.h | 1 + @@ -86266,10 +87096,10 @@ 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 244759b..7cebca0 100644 +index 836b061..e6d1fd1 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig -@@ -341,6 +341,17 @@ config HW_RANDOM_TPM +@@ -320,6 +320,17 @@ config HW_RANDOM_TPM If unsure, say Y. @@ -86288,10 +87118,10 @@ index 244759b..7cebca0 100644 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 +index 199ed283..1299292 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile -@@ -29,4 +29,5 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o +@@ -28,4 +28,5 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o @@ -86425,10 +87255,10 @@ index 0000000..340f004 2.0.3 -From a5fbd670dd3cbc4f88f171b5d1891c50a266cd27 Mon Sep 17 00:00:00 2001 +From 052f1d58548c436f372fe61074f8aa0cb7312631 Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 12/81] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 14/69] 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 @@ -87173,1287 +88003,10 @@ index 0000000..57ffacf 2.0.3 -From 85f2e35d64890063b01d29cbd7c4c1262b52060e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 8 May 2012 23:12:13 +0100 -Subject: [PATCH 13/81] Fixes for sdhci-bcm2708 - -possible fix for sdcard missing status. Thank naren - -sdcard patch improvements from naren - -sdhci-bcm2708: speed up DMA sync - -Experiments show that it doesn't really take that long to sync, so we -can reduce the poll interval slightly. Might improve performance a bit. - -sdhci-bcm2708: remove custom clock handling - -The custom clock handling code is redundant and buggy. The MMC/SDHCI -subsystem does a better job than it, so remove it for good. - -sdhci-bcm2708: add additional quirks - -Some additional quirks are needed for correct operation. -There's no SDHCI capabilities register documented, and it always reads -zero, so add SDHCI_QUIRK_MISSING_CAPS. Apparently -SDHCI_QUIRK_NO_HISPD_BIT is needed for many cards to work correctly in -high-speed mode, so add it as well. - -sdhci-bcm2708: add allow_highspeed parameter - -Add a parameter to disable high-speed mode for the few cards that -still might have problems. High-speed mode is enabled by default. - -sdhci-bcm2708: assume 50 MHz eMMC clock - -80 MHz clock isnt't suited well to be dividable to get SD clocks of 25 -MHz (default mode) or 50 MHz (high speed mode). 50 MHz are perfect to -drive the SD interface at ideal frequencies. - -Allow emmc clock to be specified as command line parameter - -sdhci-bcm2708: raise DMA sync timeout - -Commit d64b84c by accident reduced the maximum overall DMA sync -timeout. The maximum overall timeout was reduced from 100ms to 30ms, -which isn't enough for many cards. Increase it to 150ms, just to be -extra safe. According to commit 872a8ff in the MMC subsystem, some -cards require crazy long timeouts (3s), but as we're busy-waiting, -and shouldn't delay for such a long time, let's hope 150ms will be -enough for most cards. - -Use ndelay rather than udelay. Thanks lb - -Add sync_after_dma module parameter - -sdhci-bcm2708: use extension FIFO to buffer DMA transfers - -The additional FIFO might speed up transfers in some cases. - -sdhci-bcm2708: use multiblock-type transfers for single blocks - -There are issues with both single block reads (missed completion) -and writes (data loss in some cases!). Just don't do single block -transfers anymore, and treat them like multiblock transfers. This -adds a quirk for this and uses it. - -Add module parameter for missing_status quirk. sdhci-bcm2708.missing_status=0 may improve interrupt latency - -Fix spinlock recursion in sdhci-bcm2708.c - -mmc: Report 3.3V support in caps - -sdhci: Use macros for out spin lock/unlock functions to reduce diffs with upstream code - -sdhci: sdhci_bcm2708_quirk_voltage_broken appears to be a no-op - -sdhci: sdhci_bcm2708_uhs_broken should be handled through caps reported - -Add low-latency mode to sdcard driver. Disable with sdhci-bcm2708.enable_llm=0. Thanks ddv2005. - -Allow the number of cycles delay between sdcard peripheral writes to be specified on command line with sdhci-bcm2708.cycle_delay - -Lazy CRC quirk: Implemented retrying mechanisms for SD SSR and SCR, disabled missing_status and spurious CRC ACMD51 quirks by default (should be fixed by the retrying-mechanishm) - -mmc: suppress sdcard warnings we are happy about by default - -sdhci-bcm2807: Increase sync_after_dma timeout - -The current timeout is being hit with some cards that complete successfully with a longer timeout. -The timeout is not handled well, and is believed to be a code path that causes corruption. -872a8ff suggests that crappy cards can take up to 3 seconds to respond - -remove suspend/resume - -fix sign in sdhci_bcm2708_raw_writel wait calculation - -The ns_wait variable is intended to hold a lower bound on the number of nanoseconds that have elapsed since the last sdhci register write. However, the actual calculation of it was incorrect, as the subtraction was inverted. This commit fixes the calculation. - -Note that this correction has no bearing when running with the default cycle_delay of 2 and the default clock rate of 50 MHz, under which conditions ns_2clk is 40 nanoseconds and ns_wait, regardless of whether the subtraction is done correctly or incorrectly, cannot possibly be less than 40 except for during the one-microsecond period just before the tick counter wraps around to meet last_write_hpt (i.e., approximately 4295 seconds after the preceding sdhci register write). The correction in this commit only comes into play if ns_2clk > 1000, which requires a cycle_delay of 51 or greater when using the default clock rate. Under those conditions, sdhci_bcm2708_raw_writel will not wait for the full cycle_delay count if at least 1000 nanoseconds have elapsed since the last register write. - -sdhci: Only do one iteration of PIO reading loop - -Changed wording on logging. Previously, we received errors like this: -mmc0: could read SD Status register (SSR) at the 3th attempt -A more sensible response is now returned. -A typo also fixed in comments. ---- - drivers/mmc/card/block.c | 2 +- - drivers/mmc/core/sd.c | 110 +++++++++++++++-- - drivers/mmc/host/sdhci-bcm2708.c | 254 ++++++++++++++++++--------------------- - drivers/mmc/host/sdhci.c | 180 ++++++++++++++++++++------- - drivers/mmc/host/sdhci.h | 8 +- - include/linux/mmc/host.h | 1 + - include/linux/mmc/sdhci.h | 1 + - 7 files changed, 365 insertions(+), 191 deletions(-) - -diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c -index 452782b..eee5aef 100644 ---- a/drivers/mmc/card/block.c -+++ b/drivers/mmc/card/block.c -@@ -1404,7 +1404,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, - brq->data.blocks = 1; - } - -- if (brq->data.blocks > 1 || do_rel_wr) { -+ if (brq->data.blocks > 1 || do_rel_wr || card->host->caps2 & MMC_CAP2_FORCE_MULTIBLOCK) { - /* SPI multiblock writes terminate using a special - * token, not a STOP_TRANSMISSION request. - */ -diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c -index 2dd359d..f7753bf 100644 ---- a/drivers/mmc/core/sd.c -+++ b/drivers/mmc/core/sd.c -@@ -15,6 +15,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -67,6 +69,15 @@ static const unsigned int sd_au_size[] = { - __res & __mask; \ - }) - -+// timeout for tries -+static const unsigned long retry_timeout_ms= 10*1000; -+ -+// try at least 10 times, even if timeout is reached -+static const int retry_min_tries= 10; -+ -+// delay between tries -+static const unsigned long retry_delay_ms= 10; -+ - /* - * Given the decoded CSD structure, decode the raw CID to our CID structure. - */ -@@ -219,12 +230,63 @@ static int mmc_decode_scr(struct mmc_card *card) - } - - /* -- * Fetch and process SD Status register. -+ * Fetch and process SD Configuration Register. -+ */ -+static int mmc_read_scr(struct mmc_card *card) -+{ -+ unsigned long timeout_at; -+ int err, tries; -+ -+ timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms ); -+ tries= 0; -+ -+ while( tries < retry_min_tries || time_before( jiffies, timeout_at ) ) -+ { -+ unsigned long delay_at; -+ tries++; -+ -+ err = mmc_app_send_scr(card, card->raw_scr); -+ if( !err ) -+ break; // success!!! -+ -+ touch_nmi_watchdog(); // we are still alive! -+ -+ // delay -+ delay_at= jiffies + msecs_to_jiffies( retry_delay_ms ); -+ while( time_before( jiffies, delay_at ) ) -+ { -+ mdelay( 1 ); -+ touch_nmi_watchdog(); // we are still alive! -+ } -+ } -+ -+ if( err) -+ { -+ pr_err("%s: failed to read SD Configuration register (SCR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err ); -+ return err; -+ } -+ -+ if( tries > 1 ) -+ { -+ pr_info("%s: could read SD Configuration register (SCR) at the %dth attempt\n", mmc_hostname(card->host), tries ); -+ } -+ -+ err = mmc_decode_scr(card); -+ if (err) -+ return err; -+ -+ return err; -+} -+ -+/* -+ * Fetch and process SD Status Register. - */ - static int mmc_read_ssr(struct mmc_card *card) - { -+ unsigned long timeout_at; - unsigned int au, es, et, eo; - int err, i; -+ int tries; - u32 *ssr; - - if (!(card->csd.cmdclass & CCC_APP_SPEC)) { -@@ -237,14 +299,40 @@ static int mmc_read_ssr(struct mmc_card *card) - if (!ssr) - return -ENOMEM; - -- err = mmc_app_sd_status(card, ssr); -- if (err) { -- pr_warning("%s: problem reading SD Status " -- "register.\n", mmc_hostname(card->host)); -- err = 0; -+ timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms ); -+ tries= 0; -+ -+ while( tries < retry_min_tries || time_before( jiffies, timeout_at ) ) -+ { -+ unsigned long delay_at; -+ tries++; -+ -+ err= mmc_app_sd_status(card, ssr); -+ if( !err ) -+ break; // sucess!!! -+ -+ touch_nmi_watchdog(); // we are still alive! -+ -+ // delay -+ delay_at= jiffies + msecs_to_jiffies( retry_delay_ms ); -+ while( time_before( jiffies, delay_at ) ) -+ { -+ mdelay( 1 ); -+ touch_nmi_watchdog(); // we are still alive! -+ } -+ } -+ -+ if( err) -+ { -+ pr_err("%s: failed to read SD Status register (SSR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err ); - goto out; - } - -+ if( tries > 1 ) -+ { -+ pr_info("%s: read SD Status register (SSR) after %d attempts\n", mmc_hostname(card->host), tries ); -+ } -+ - for (i = 0; i < 16; i++) - ssr[i] = be32_to_cpu(ssr[i]); - -@@ -826,14 +914,10 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, - - if (!reinit) { - /* -- * Fetch SCR from card. -+ * Fetch and decode SD Configuration register. - */ -- err = mmc_app_send_scr(card, card->raw_scr); -- if (err) -- return err; -- -- err = mmc_decode_scr(card); -- if (err) -+ err = mmc_read_scr(card); -+ if( err ) - return err; - - /* -diff --git a/drivers/mmc/host/sdhci-bcm2708.c b/drivers/mmc/host/sdhci-bcm2708.c -index d8ef77c..3173c18 100644 ---- a/drivers/mmc/host/sdhci-bcm2708.c -+++ b/drivers/mmc/host/sdhci-bcm2708.c -@@ -51,7 +51,6 @@ - #undef CONFIG_MMC_SDHCI_BCM2708_DMA - #define CONFIG_MMC_SDHCI_BCM2708_DMA y - --#define USE_SYNC_AFTER_DMA - #ifdef CONFIG_MMC_SDHCI_BCM2708_DMA - /* #define CHECK_DMA_USE */ - #endif -@@ -73,7 +72,12 @@ - #define BCM2708_SDHCI_SLEEP_TIMEOUT 1000 /* msecs */ - - /* Mhz clock that the EMMC core is running at. Should match the platform clockman settings */ --#define BCM2708_EMMC_CLOCK_FREQ 80000000 -+#define BCM2708_EMMC_CLOCK_FREQ 50000000 -+ -+#define REG_EXRDFIFO_EN 0x80 -+#define REG_EXRDFIFO_CFG 0x84 -+ -+int cycle_delay=2; - - /*****************************************************************************\ - * * -@@ -129,6 +133,14 @@ static inline unsigned long int since_ns(hptime_t t) - return (unsigned long)((hptime() - t) * HPTIME_CLK_NS); - } - -+static bool allow_highspeed = 1; -+static int emmc_clock_freq = BCM2708_EMMC_CLOCK_FREQ; -+static bool sync_after_dma = 1; -+static bool missing_status = 1; -+static bool spurious_crc_acmd51 = 0; -+bool enable_llm = 1; -+bool extra_messages = 0; -+ - #if 0 - static void hptime_test(void) - { -@@ -241,19 +253,19 @@ static void sdhci_bcm2708_raw_writel(struct sdhci_host *host, u32 val, int reg) - /* host->clock is the clock freq in Hz */ - static hptime_t last_write_hpt; - hptime_t now = hptime(); -- ns_2clk = 2000000000/host->clock; -+ ns_2clk = cycle_delay*1000000/(host->clock/1000); - - if (now == last_write_hpt || now == last_write_hpt+1) { - /* we can't guarantee any significant time has - * passed - we'll have to wait anyway ! */ -- udelay((ns_2clk+1000-1)/1000); -+ ndelay(ns_2clk); - } else - { - /* we must have waited at least this many ns: */ - unsigned int ns_wait = HPTIME_CLK_NS * -- (last_write_hpt - now - 1); -+ (now - last_write_hpt - 1); - if (ns_wait < ns_2clk) -- udelay((ns_2clk-ns_wait+500)/1000); -+ ndelay(ns_2clk - ns_wait); - } - last_write_hpt = now; - } -@@ -269,13 +281,13 @@ static void sdhci_bcm2708_raw_writel(struct sdhci_host *host, u32 val, int reg) - ier &= ~SDHCI_INT_DATA_TIMEOUT; - writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); - timeout_disabled = true; -- udelay((ns_2clk+1000-1)/1000); -+ ndelay(ns_2clk); - } else if (timeout_disabled) { - ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE); - ier |= SDHCI_INT_DATA_TIMEOUT; - writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); - timeout_disabled = false; -- udelay((ns_2clk+1000-1)/1000); -+ ndelay(ns_2clk); - } - #endif - writel(val, host->ioaddr + reg); -@@ -353,68 +365,9 @@ void sdhci_bcm2708_writeb(struct sdhci_host *host, u8 val, int reg) - - static unsigned int sdhci_bcm2708_get_max_clock(struct sdhci_host *host) - { -- return 20000000; // this value is in Hz (20MHz) --} -- --static unsigned int sdhci_bcm2708_get_timeout_clock(struct sdhci_host *host) --{ -- if(host->clock) -- return (host->clock / 1000); // this value is in kHz (100MHz) -- else -- return (sdhci_bcm2708_get_max_clock(host) / 1000); -+ return emmc_clock_freq; - } - --static void sdhci_bcm2708_set_clock(struct sdhci_host *host, unsigned int clock) --{ -- int div = 0; -- u16 clk = 0; -- unsigned long timeout; -- -- if (clock == host->clock) -- return; -- -- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); -- -- if (clock == 0) -- goto out; -- -- if (BCM2708_EMMC_CLOCK_FREQ <= clock) -- div = 1; -- else { -- for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { -- if ((BCM2708_EMMC_CLOCK_FREQ / div) <= clock) -- break; -- } -- } -- -- DBG( "desired SD clock: %d, actual: %d\n", -- clock, BCM2708_EMMC_CLOCK_FREQ / div); -- -- clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; -- clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) -- << SDHCI_DIVIDER_HI_SHIFT; -- clk |= SDHCI_CLOCK_INT_EN; -- -- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -- -- timeout = 20; -- while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) -- & SDHCI_CLOCK_INT_STABLE)) { -- if (timeout == 0) { -- printk(KERN_ERR "%s: Internal clock never " -- "stabilised.\n", mmc_hostname(host->mmc)); -- return; -- } -- timeout--; -- mdelay(1); -- } -- -- clk |= SDHCI_CLOCK_CARD_EN; -- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); --out: -- host->clock = clock; -- } -- - /*****************************************************************************\ - * * - * DMA Operation * -@@ -695,11 +648,11 @@ void - sdhci_bcm2708_platdma_reset(struct sdhci_host *host, struct mmc_data *data) - { - struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host); -- unsigned long flags; -+// unsigned long flags; - - BUG_ON(NULL == host); - -- spin_lock_irqsave(&host->lock, flags); -+// spin_lock_irqsave(&host->lock, flags); - - if (host_priv->dma_wanted) { - if (NULL == data) { -@@ -720,13 +673,16 @@ sdhci_bcm2708_platdma_reset(struct sdhci_host *host, struct mmc_data *data) - cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS); - - if (!(BCM2708_DMA_ACTIVE & cs)) -- printk(KERN_INFO "%s: missed completion of " -+ { -+ if (extra_messages) -+ printk(KERN_INFO "%s: missed completion of " - "cmd %d DMA (%d/%d [%d]/[%d]) - " - "ignoring it\n", - mmc_hostname(host->mmc), - host->last_cmdop, - host_priv->sg_done, sg_todo, - host_priv->sg_ix+1, sg_len); -+ } - else - printk(KERN_INFO "%s: resetting ongoing cmd %d" - "DMA before %d/%d [%d]/[%d] complete\n", -@@ -779,7 +735,7 @@ sdhci_bcm2708_platdma_reset(struct sdhci_host *host, struct mmc_data *data) - #endif - } - -- spin_unlock_irqrestore(&host->lock, flags); -+// spin_unlock_irqrestore(&host->lock, flags); - } - - -@@ -792,11 +748,11 @@ static void sdhci_bcm2708_dma_complete_irq(struct sdhci_host *host, - int sg_len; - int sg_ix; - int sg_todo; -- unsigned long flags; -+// unsigned long flags; - - BUG_ON(NULL == host); - -- spin_lock_irqsave(&host->lock, flags); -+// spin_lock_irqsave(&host->lock, flags); - data = host->data; - - #ifdef CHECK_DMA_USE -@@ -821,7 +777,7 @@ static void sdhci_bcm2708_dma_complete_irq(struct sdhci_host *host, - - if (NULL == data) { - DBG("PDMA unused completion - status 0x%X\n", dma_cs); -- spin_unlock_irqrestore(&host->lock, flags); -+// spin_unlock_irqrestore(&host->lock, flags); - return; - } - sg = data->sg; -@@ -878,40 +834,34 @@ static void sdhci_bcm2708_dma_complete_irq(struct sdhci_host *host, - SDHCI_INT_SPACE_AVAIL); - } - } else { --#ifdef USE_SYNC_AFTER_DMA -- /* On the Arasan controller the stop command (which will be -- scheduled after this completes) does not seem to work -- properly if we allow it to be issued when we are -- transferring data to/from the SD card. -- We get CRC and DEND errors unless we wait for -- the SD controller to finish reading/writing to the card. */ -- u32 state_mask; -- int timeout=1000000; -- hptime_t now = hptime(); -- -- DBG("PDMA over - sync card\n"); -- if (data->flags & MMC_DATA_READ) -- state_mask = SDHCI_DOING_READ; -- else -- state_mask = SDHCI_DOING_WRITE; -- -- while (0 != (sdhci_bcm2708_raw_readl(host, -- SDHCI_PRESENT_STATE) & -- state_mask) && --timeout > 0) -- continue; -+ if (sync_after_dma) { -+ /* On the Arasan controller the stop command (which will be -+ scheduled after this completes) does not seem to work -+ properly if we allow it to be issued when we are -+ transferring data to/from the SD card. -+ We get CRC and DEND errors unless we wait for -+ the SD controller to finish reading/writing to the card. */ -+ u32 state_mask; -+ int timeout=3*1000*1000; -+ -+ DBG("PDMA over - sync card\n"); -+ if (data->flags & MMC_DATA_READ) -+ state_mask = SDHCI_DOING_READ; -+ else -+ state_mask = SDHCI_DOING_WRITE; - -- if (1000000-timeout > 4000) /*ave. is about 3250*/ -- DBG("%s: note - long %s sync %luns - " -- "%d its.\n", -- mmc_hostname(host->mmc), -- data->flags & MMC_DATA_READ? "read": "write", -- since_ns(now), 1000000-timeout); -- if (timeout <= 0) -- printk(KERN_ERR"%s: final %s to SD card still " -- "running\n", -- mmc_hostname(host->mmc), -- data->flags & MMC_DATA_READ? "read": "write"); --#endif -+ while (0 != (sdhci_bcm2708_raw_readl(host, SDHCI_PRESENT_STATE) -+ & state_mask) && --timeout > 0) -+ { -+ udelay(1); -+ continue; -+ } -+ if (timeout <= 0) -+ printk(KERN_ERR"%s: final %s to SD card still " -+ "running\n", -+ mmc_hostname(host->mmc), -+ data->flags & MMC_DATA_READ? "read": "write"); -+ } - if (host_priv->complete) { - (*host_priv->complete)(host); - DBG("PDMA %s complete\n", -@@ -920,7 +870,7 @@ static void sdhci_bcm2708_dma_complete_irq(struct sdhci_host *host, - SDHCI_INT_SPACE_AVAIL); - } - } -- spin_unlock_irqrestore(&host->lock, flags); -+// spin_unlock_irqrestore(&host->lock, flags); - } - - static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id) -@@ -929,12 +879,11 @@ static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id) - struct sdhci_host *host = dev_id; - struct sdhci_bcm2708_priv *host_priv = SDHCI_HOST_PRIV(host); - u32 dma_cs; /* control and status register */ -- unsigned long flags; - - BUG_ON(NULL == dev_id); - BUG_ON(NULL == host_priv->dma_chan_base); - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock(host); - - dma_cs = readl(host_priv->dma_chan_base + BCM2708_DMA_CS); - -@@ -958,7 +907,8 @@ static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id) - - if (!host_priv->dma_wanted) { - /* ignore this interrupt - it was reset */ -- printk(KERN_INFO "%s: DMA IRQ %X ignored - " -+ if (extra_messages) -+ printk(KERN_INFO "%s: DMA IRQ %X ignored - " - "results were reset\n", - mmc_hostname(host->mmc), dma_cs); - #ifdef CHECK_DMA_USE -@@ -975,8 +925,7 @@ static irqreturn_t sdhci_bcm2708_dma_irq(int irq, void *dev_id) - - result = IRQ_HANDLED; - } -- -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock(host); - - return result; - } -@@ -1019,10 +968,12 @@ static ssize_t attr_dma_store(struct device *_dev, - int on = simple_strtol(buf, NULL, 0); - if (on) { - host->flags |= SDHCI_USE_PLATDMA; -+ sdhci_bcm2708_writel(host, 1, REG_EXRDFIFO_EN); - printk(KERN_INFO "%s: DMA enabled\n", - mmc_hostname(host->mmc)); - } else { - host->flags &= ~(SDHCI_USE_PLATDMA | SDHCI_REQ_USE_DMA); -+ sdhci_bcm2708_writel(host, 0, REG_EXRDFIFO_EN); - printk(KERN_INFO "%s: DMA disabled\n", - mmc_hostname(host->mmc)); - } -@@ -1126,7 +1077,7 @@ static int sdhci_bcm2708_suspend(struct platform_device *dev, pm_message_t state - int ret = 0; - - if (host->mmc) { -- ret = mmc_suspend_host(host->mmc); -+ //ret = mmc_suspend_host(host->mmc); - } - - return ret; -@@ -1139,7 +1090,7 @@ static int sdhci_bcm2708_resume(struct platform_device *dev) - int ret = 0; - - if (host->mmc) { -- ret = mmc_resume_host(host->mmc); -+ //ret = mmc_resume_host(host->mmc); - } - - return ret; -@@ -1158,19 +1109,14 @@ static unsigned int sdhci_bcm2708_quirk_extra_ints(struct sdhci_host *host) - return 1; - } - --static unsigned int sdhci_bcm2708_quirk_spurious_crc(struct sdhci_host *host) -+static unsigned int sdhci_bcm2708_quirk_spurious_crc_acmd51(struct sdhci_host *host) - { - return 1; - } - --static unsigned int sdhci_bcm2708_quirk_voltage_broken(struct sdhci_host *host) -+static unsigned int sdhci_bcm2708_missing_status(struct sdhci_host *host) - { -- return 1; --} -- --static unsigned int sdhci_bcm2708_uhs_broken(struct sdhci_host *host) --{ -- return 1; -+ return 1; - } - - /***************************************************************************** \ -@@ -1190,11 +1136,7 @@ static struct sdhci_ops sdhci_bcm2708_ops = { - #else - #error The BCM2708 SDHCI driver needs CONFIG_MMC_SDHCI_IO_ACCESSORS to be set - #endif -- //.enable_dma = NULL, -- .set_clock = sdhci_bcm2708_set_clock, - .get_max_clock = sdhci_bcm2708_get_max_clock, -- //.get_min_clock = NULL, -- .get_timeout_clock = sdhci_bcm2708_get_timeout_clock, - - #ifdef CONFIG_MMC_SDHCI_BCM2708_DMA - // Platform DMA operations -@@ -1203,9 +1145,6 @@ static struct sdhci_ops sdhci_bcm2708_ops = { - .pdma_reset = sdhci_bcm2708_platdma_reset, - #endif - .extra_ints = sdhci_bcm2708_quirk_extra_ints, -- .spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc, -- .voltage_broken = sdhci_bcm2708_quirk_voltage_broken, -- .uhs_broken = sdhci_bcm2708_uhs_broken, - }; - - /*****************************************************************************\ -@@ -1244,15 +1183,30 @@ static int sdhci_bcm2708_probe(struct platform_device *pdev) - ret = PTR_ERR(host); - goto err; - } -+ if (missing_status) { -+ sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status; -+ } -+ -+ if( spurious_crc_acmd51 ) { -+ sdhci_bcm2708_ops.spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc_acmd51; -+ } -+ -+ -+ printk("sdhci: %s low-latency mode\n",enable_llm?"Enable":"Disable"); - - host->hw_name = "BCM2708_Arasan"; - host->ops = &sdhci_bcm2708_ops; - host->irq = platform_get_irq(pdev, 0); -+ host->second_irq = 0; - - host->quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | - SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | - SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | -- SDHCI_QUIRK_NONSTANDARD_CLOCK; -+ SDHCI_QUIRK_MISSING_CAPS | -+ SDHCI_QUIRK_NO_HISPD_BIT | -+ (sync_after_dma ? 0:SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12); -+ -+ - #ifdef CONFIG_MMC_SDHCI_BCM2708_DMA - host->flags = SDHCI_USE_PLATDMA; - #endif -@@ -1305,17 +1259,24 @@ static int sdhci_bcm2708_probe(struct platform_device *pdev) - host_priv->dma_chan = ret; - - ret = request_irq(host_priv->dma_irq, sdhci_bcm2708_dma_irq, -- IRQF_SHARED, DRIVER_NAME " (dma)", host); -+ 0 /*IRQF_SHARED*/, DRIVER_NAME " (dma)", host); - if (ret) { - dev_err(&pdev->dev, "cannot set DMA IRQ\n"); - goto err_add_dma_irq; - } -+ host->second_irq = host_priv->dma_irq; - DBG("DMA CBs %p handle %08X DMA%d %p DMA IRQ %d\n", - host_priv->cb_base, (unsigned)host_priv->cb_handle, - host_priv->dma_chan, host_priv->dma_chan_base, - host_priv->dma_irq); - -- host->mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; -+ // we support 3.3V -+ host->caps |= SDHCI_CAN_VDD_330; -+ if (allow_highspeed) -+ host->mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; -+ -+ /* single block writes cause data loss with some SD cards! */ -+ host->mmc->caps2 |= MMC_CAP2_FORCE_MULTIBLOCK; - #endif - - ret = sdhci_add_host(host); -@@ -1327,6 +1288,12 @@ static int sdhci_bcm2708_probe(struct platform_device *pdev) - ret = device_create_file(&pdev->dev, &dev_attr_dma_wait); - ret = device_create_file(&pdev->dev, &dev_attr_status); - -+#ifdef CONFIG_MMC_SDHCI_BCM2708_DMA -+ /* enable extension fifo for paced DMA transfers */ -+ sdhci_bcm2708_writel(host, 1, REG_EXRDFIFO_EN); -+ sdhci_bcm2708_writel(host, 4, REG_EXRDFIFO_CFG); -+#endif -+ - printk(KERN_INFO "%s: BCM2708 SDHC host at 0x%08llx DMA %d IRQ %d\n", - mmc_hostname(host->mmc), (unsigned long long)iomem->start, - host_priv->dma_chan, host_priv->dma_irq); -@@ -1418,7 +1385,26 @@ static void __exit sdhci_drv_exit(void) - module_init(sdhci_drv_init); - module_exit(sdhci_drv_exit); - -+module_param(allow_highspeed, bool, 0444); -+module_param(emmc_clock_freq, int, 0444); -+module_param(sync_after_dma, bool, 0444); -+module_param(missing_status, bool, 0444); -+module_param(spurious_crc_acmd51, bool, 0444); -+module_param(enable_llm, bool, 0444); -+module_param(cycle_delay, int, 0444); -+module_param(extra_messages, bool, 0444); -+ - MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver"); - MODULE_AUTHOR("Broadcom "); - MODULE_LICENSE("GPL v2"); - MODULE_ALIAS("platform:"DRIVER_NAME); -+ -+MODULE_PARM_DESC(allow_highspeed, "Allow high speed transfers modes"); -+MODULE_PARM_DESC(emmc_clock_freq, "Specify the speed of emmc clock"); -+MODULE_PARM_DESC(sync_after_dma, "Block in driver until dma complete"); -+MODULE_PARM_DESC(missing_status, "Use the missing status quirk"); -+MODULE_PARM_DESC(spurious_crc_acmd51, "Use the spurious crc quirk for reading SCR (ACMD51)"); -+MODULE_PARM_DESC(enable_llm, "Enable low-latency mode"); -+MODULE_PARM_DESC(extra_messages, "Enable more sdcard warning messages"); -+ -+ -diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -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) - * Low level functions * - * * - \*****************************************************************************/ -+extern bool enable_llm; -+static int sdhci_locked=0; -+void sdhci_spin_lock(struct sdhci_host *host) -+{ -+ spin_lock(&host->lock); -+#ifdef CONFIG_PREEMPT -+ if(enable_llm) -+ { -+ disable_irq_nosync(host->irq); -+ if(host->second_irq) -+ disable_irq_nosync(host->second_irq); -+ local_irq_enable(); -+ } -+#endif -+} -+ -+void sdhci_spin_unlock(struct sdhci_host *host) -+{ -+#ifdef CONFIG_PREEMPT -+ if(enable_llm) -+ { -+ local_irq_disable(); -+ if(host->second_irq) -+ enable_irq(host->second_irq); -+ enable_irq(host->irq); -+ } -+#endif -+ spin_unlock(&host->lock); -+} -+ -+void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags) -+{ -+#ifdef CONFIG_PREEMPT -+ if(enable_llm) -+ { -+ while(sdhci_locked) -+ { -+ preempt_schedule(); -+ } -+ spin_lock_irqsave(&host->lock,*flags); -+ disable_irq(host->irq); -+ if(host->second_irq) -+ disable_irq(host->second_irq); -+ local_irq_enable(); -+ } -+ else -+#endif -+ spin_lock_irqsave(&host->lock,*flags); -+} -+ -+void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags) -+{ -+#ifdef CONFIG_PREEMPT -+ if(enable_llm) -+ { -+ local_irq_disable(); -+ if(host->second_irq) -+ enable_irq(host->second_irq); -+ enable_irq(host->irq); -+ } -+#endif -+ spin_unlock_irqrestore(&host->lock,flags); -+} -+ -+static void sdhci_spin_enable_schedule(struct sdhci_host *host) -+{ -+#ifdef CONFIG_PREEMPT -+ if(enable_llm) -+ { -+ sdhci_locked = 1; -+ preempt_enable(); -+ } -+#endif -+} -+ -+static void sdhci_spin_disable_schedule(struct sdhci_host *host) -+{ -+#ifdef CONFIG_PREEMPT -+ if(enable_llm) -+ { -+ preempt_disable(); -+ sdhci_locked = 0; -+ } -+#endif -+} -+ -+ -+#undef spin_lock_irqsave -+#define spin_lock_irqsave(host_lock, flags) sdhci_spin_lock_irqsave(container_of(host_lock, struct sdhci_host, lock), &flags) -+#define spin_unlock_irqrestore(host_lock, flags) sdhci_spin_unlock_irqrestore(container_of(host_lock, struct sdhci_host, lock), flags) -+ -+#define spin_lock(host_lock) sdhci_spin_lock(container_of(host_lock, struct sdhci_host, lock)) -+#define spin_unlock(host_lock) sdhci_spin_unlock(container_of(host_lock, struct sdhci_host, lock)) - - static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set) - { -@@ -300,7 +393,7 @@ static void sdhci_led_control(struct led_classdev *led, - struct sdhci_host *host = container_of(led, struct sdhci_host, led); - unsigned long flags; - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - if (host->runtime_suspended) - goto out; -@@ -310,7 +403,7 @@ static void sdhci_led_control(struct led_classdev *led, - else - sdhci_activate_led(host); - out: -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - #endif - -@@ -457,6 +550,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host, u32 intstate) - break; - state = sdhci_readl(host, SDHCI_PRESENT_STATE); - available = state & mask; -+ break; - } - - DBG("PIO transfer complete - %d blocks left.\n", host->blocks); -@@ -1023,7 +1117,9 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) - return; - } - timeout--; -+ sdhci_spin_enable_schedule(host); - mdelay(1); -+ sdhci_spin_disable_schedule(host); - } - DBG("send cmd %d - wait 0x%X irq 0x%x\n", cmd->opcode, mask, - sdhci_readl(host, SDHCI_INT_STATUS)); -@@ -1256,7 +1352,9 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) - return; - } - timeout--; -+ sdhci_spin_enable_schedule(host); - mdelay(1); -+ sdhci_spin_disable_schedule(host); - } - - clk |= SDHCI_CLOCK_CARD_EN; -@@ -1357,7 +1455,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) - - sdhci_runtime_pm_get(host); - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - WARN_ON(host->mrq != NULL); - -@@ -1422,9 +1520,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) - */ - host->mrq = NULL; - -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - sdhci_execute_tuning(mmc, tuning_opcode); -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - /* Restore original mmc_request structure */ - host->mrq = mrq; -@@ -1438,7 +1536,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) - } - - mmiowb(); -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - - static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) -@@ -1447,10 +1545,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) - int vdd_bit = -1; - u8 ctrl; - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - if (host->flags & SDHCI_DEVICE_DEAD) { -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - if (host->vmmc && ios->power_mode == MMC_POWER_OFF) - mmc_regulator_set_ocr(host->mmc, host->vmmc, 0); - return; -@@ -1478,9 +1576,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) - vdd_bit = sdhci_set_power(host, ios->vdd); - - if (host->vmmc && vdd_bit != -1) { -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit); -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - } - - if (host->ops->platform_send_init_74_clocks) -@@ -1519,7 +1617,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) - else - ctrl &= ~SDHCI_CTRL_HISPD; - -- if (host->version >= SDHCI_SPEC_300 && !(host->ops->uhs_broken)) { -+ if (host->version >= SDHCI_SPEC_300) { - u16 clk, ctrl_2; - - /* In case of UHS-I modes, set High Speed Enable */ -@@ -1617,7 +1715,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) - sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - - mmiowb(); -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - - static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -@@ -1665,7 +1763,7 @@ static int sdhci_check_ro(struct sdhci_host *host) - unsigned long flags; - int is_readonly; - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - if (host->flags & SDHCI_DEVICE_DEAD) - is_readonly = 0; -@@ -1675,7 +1773,7 @@ static int sdhci_check_ro(struct sdhci_host *host) - is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE) - & SDHCI_WRITE_PROTECT); - -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - - /* This quirk needs to be replaced by a callback-function later */ - return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ? -@@ -1748,9 +1846,9 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) - struct sdhci_host *host = mmc_priv(mmc); - unsigned long flags; - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - sdhci_enable_sdio_irq_nolock(host, enable); -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - - static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, -@@ -2100,7 +2198,7 @@ static void sdhci_card_event(struct mmc_host *mmc) - if (host->ops->card_event) - host->ops->card_event(host); - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - /* Check host->mrq first in case we are runtime suspended */ - if (host->mrq && !sdhci_do_get_cd(host)) { -@@ -2116,7 +2214,7 @@ static void sdhci_card_event(struct mmc_host *mmc) - tasklet_schedule(&host->finish_tasklet); - } - -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - - static const struct mmc_host_ops sdhci_ops = { -@@ -2155,14 +2253,14 @@ static void sdhci_tasklet_finish(unsigned long param) - - host = (struct sdhci_host*)param; - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - /* - * If this tasklet gets rescheduled while running, it will - * be run again afterwards but without any active request. - */ - if (!host->mrq) { -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - return; - } - -@@ -2200,7 +2298,7 @@ static void sdhci_tasklet_finish(unsigned long param) - #endif - - mmiowb(); -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - - mmc_request_done(host->mmc, mrq); - sdhci_runtime_pm_put(host); -@@ -2213,7 +2311,7 @@ static void sdhci_timeout_timer(unsigned long data) - - host = (struct sdhci_host*)data; - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - if (host->mrq) { - pr_err("%s: Timeout waiting for hardware " -@@ -2234,7 +2332,7 @@ static void sdhci_timeout_timer(unsigned long data) - } - - mmiowb(); -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - - 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; - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - host->flags |= SDHCI_NEEDS_RETUNING; - -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - - /*****************************************************************************\ -@@ -2472,10 +2570,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) - u32 intmask, unexpected = 0; - int cardint = 0, max_loops = 16; - -- spin_lock(&host->lock); -+ sdhci_spin_lock(host); - - if (host->runtime_suspended) { -- spin_unlock(&host->lock); -+ sdhci_spin_unlock(host); - return IRQ_NONE; - } - -@@ -2585,7 +2683,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) - if (intmask && --max_loops) - goto again; - out: -- spin_unlock(&host->lock); -+ sdhci_spin_unlock(host); - - if (unexpected) { - pr_err("%s: Unexpected interrupt 0x%08x.\n", -@@ -2671,7 +2769,7 @@ int sdhci_resume_host(struct sdhci_host *host) - } - - if (!device_may_wakeup(mmc_dev(host->mmc))) { -- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, -+ ret = request_irq(host->irq, sdhci_irq, 0 /*IRQF_SHARED*/, - mmc_hostname(host->mmc), host); - if (ret) - return ret; -@@ -2747,15 +2845,15 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) - host->flags &= ~SDHCI_NEEDS_RETUNING; - } - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - - synchronize_irq(host->irq); - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - host->runtime_suspended = true; -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - - return ret; - } -@@ -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)) { -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - sdhci_enable_preset_value(host, true); -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - - /* Set the re-tuning expiration flag */ - if (host->flags & SDHCI_USING_RETUNING_TIMER) - host->flags |= SDHCI_NEEDS_RETUNING; - -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - host->runtime_suspended = false; - -@@ -2801,7 +2899,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) - /* Enable Card Detection */ - sdhci_enable_card_detection(host); - -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - - return ret; - } -@@ -3298,8 +3396,8 @@ int sdhci_add_host(struct sdhci_host *host) - - sdhci_init(host, 0); - -- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, -- mmc_hostname(mmc), host); -+ ret = request_irq(host->irq, sdhci_irq, 0 /*IRQF_SHARED*/, -+ mmc_hostname(mmc), host); - if (ret) { - pr_err("%s: Failed to request IRQ %d: %d\n", - mmc_hostname(mmc), host->irq, ret); -@@ -3360,7 +3458,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) - unsigned long flags; - - if (dead) { -- spin_lock_irqsave(&host->lock, flags); -+ sdhci_spin_lock_irqsave(host, &flags); - - host->flags |= SDHCI_DEVICE_DEAD; - -@@ -3372,7 +3470,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) - tasklet_schedule(&host->finish_tasklet); - } - -- spin_unlock_irqrestore(&host->lock, flags); -+ sdhci_spin_unlock_irqrestore(host, flags); - } - - sdhci_disable_card_detection(host); -diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h -index 6857875..649f3cf 100644 ---- a/drivers/mmc/host/sdhci.h -+++ b/drivers/mmc/host/sdhci.h -@@ -300,8 +300,6 @@ struct sdhci_ops { - struct mmc_data *data); - unsigned int (*extra_ints)(struct sdhci_host *host); - unsigned int (*spurious_crc_acmd51)(struct sdhci_host *host); -- unsigned int (*voltage_broken)(struct sdhci_host *host); -- unsigned int (*uhs_broken)(struct sdhci_host *host); - unsigned int (*missing_status)(struct sdhci_host *host); - - void (*hw_reset)(struct sdhci_host *host); -@@ -445,4 +443,10 @@ extern int sdhci_runtime_suspend_host(struct sdhci_host *host); - extern int sdhci_runtime_resume_host(struct sdhci_host *host); - #endif - -+extern void sdhci_spin_lock_irqsave(struct sdhci_host *host,unsigned long *flags); -+extern void sdhci_spin_unlock_irqrestore(struct sdhci_host *host,unsigned long flags); -+extern void sdhci_spin_lock(struct sdhci_host *host); -+extern void sdhci_spin_unlock(struct sdhci_host *host); -+ -+ - #endif /* __SDHCI_HW_H */ -diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h -index cb61ea4..27b1da6 100644 ---- a/include/linux/mmc/host.h -+++ b/include/linux/mmc/host.h -@@ -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_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 a968bd6..df54b9b 100644 ---- a/include/linux/mmc/sdhci.h -+++ b/include/linux/mmc/sdhci.h -@@ -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 */ - void __iomem *ioaddr; /* Mapped address */ - - const struct sdhci_ops *ops; /* Low level hw interface */ --- -2.0.3 - - -From b810a7af7a371a1f9c963ad75a3b6be5e9e6c5c1 Mon Sep 17 00:00:00 2001 +From 53092d7fda436acb280d02a403c0668a7f56cd8a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 14/81] Add cpufreq driver +Subject: [PATCH 15/69] Add cpufreq driver --- arch/arm/Kconfig | 1 + @@ -88464,10 +88017,10 @@ Subject: [PATCH 14/81] Add cpufreq driver create mode 100755 drivers/cpufreq/bcm2835-cpufreq.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index ed579ab..8c3505f 100644 +index bf32dc1..cb53c45 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -394,6 +394,7 @@ config ARCH_BCM2708 +@@ -383,6 +383,7 @@ config ARCH_BCM2708 select NEED_MACH_GPIO_H select NEED_MACH_MEMORY_H select CLKDEV_LOOKUP @@ -88476,10 +88029,10 @@ index ed579ab..8c3505f 100644 select ARM_ERRATA_411920 select MACH_BCM2708 diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm -index 5805035..59efbe6 100644 +index 7364a53..d0294fe 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm -@@ -240,6 +240,14 @@ config ARM_SPEAR_CPUFREQ +@@ -241,6 +241,14 @@ config ARM_SPEAR_CPUFREQ help This adds the CPUFreq driver support for SPEAr SOCs. @@ -88495,10 +88048,10 @@ index 5805035..59efbe6 100644 bool "TEGRA CPUFreq support" depends on ARCH_TEGRA diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index 3254f6c..0cfe6d1 100644 +index db6d9a2..a7874d1 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile -@@ -73,6 +73,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o +@@ -75,6 +75,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o @@ -88755,10 +88308,10 @@ index 0000000..7bc55bd 2.0.3 -From ef5102326c4fa37561cc64634fcffea2d5c65d43 Mon Sep 17 00:00:00 2001 +From c37dae10e13ec5f97ff409e76e888d3edd367850 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 15/81] Added hwmon/thermal driver for reporting core +Subject: [PATCH 16/69] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian --- @@ -88774,7 +88327,7 @@ Subject: [PATCH 15/81] 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 d60513f..f8820d4 100644 +index ab06b52..e66fc4b 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[] = { @@ -88803,10 +88356,10 @@ index d60513f..f8820d4 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 4af0da9..ad7c30f 100644 +index 02d3d85..ad95ee5 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig -@@ -1602,6 +1602,16 @@ config SENSORS_ULTRA45 +@@ -1624,6 +1624,16 @@ config SENSORS_ULTRA45 This driver provides support for the Ultra45 workstation environmental sensors. @@ -88824,10 +88377,10 @@ index 4af0da9..ad7c30f 100644 comment "ACPI drivers" diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index c48f987..396feed 100644 +index 3dc0f02..83b687d 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile -@@ -146,6 +146,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o +@@ -148,6 +148,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 @@ -89061,7 +88614,7 @@ index 0000000..5bbed45 + +module_platform_driver(bcm2835_hwmon_driver); diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig -index 2d51912..37fbdaa 100644 +index f9a1386..94cf128 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -196,6 +196,12 @@ config INTEL_POWERCLAMP @@ -89078,7 +88631,7 @@ index 2d51912..37fbdaa 100644 tristate "X86 package temperature thermal driver" depends on X86_THERMAL_VECTOR diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile -index 54e4ec9..dbbf4e4 100644 +index de0636a..77ea718 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o @@ -89087,8 +88640,8 @@ index 54e4ec9..dbbf4e4 100644 obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o +obj-$(CONFIG_THERMAL_BCM2835) += bcm2835-thermal.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o + obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ - obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o diff --git a/drivers/thermal/bcm2835-thermal.c b/drivers/thermal/bcm2835-thermal.c new file mode 100644 index 0000000..85fceb5 @@ -89283,10 +88836,10 @@ index 0000000..85fceb5 2.0.3 -From 9543a69c2b90bd5709083bb0a83021e4a6a45b26 Mon Sep 17 00:00:00 2001 +From e60f23ce15064909c9ae0d166161d70fd7a1fc04 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 16/81] Allow mac address to be set in smsc95xx +Subject: [PATCH 17/69] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -89294,7 +88847,7 @@ Signed-off-by: popcornmix 1 file changed, 56 insertions(+) diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c -index 424db65e..fc1ef4e 100644 +index d07bf4c..5ae60ab 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -59,6 +59,7 @@ @@ -89380,10 +88933,10 @@ index 424db65e..fc1ef4e 100644 2.0.3 -From dadd0c675f30eaeb8d41f99de0633952ebfd6bbf Mon Sep 17 00:00:00 2001 +From 00b4eab6ec2422674dcf87baf73f196e14000fa7 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 4 Nov 2013 18:56:10 +0000 -Subject: [PATCH 17/81] Add Chris Boot's i2c and spi drivers. +Subject: [PATCH 18/69] Add Chris Boot's i2c and spi drivers. i2c-bcm2708: fixed baudrate @@ -89460,7 +89013,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 f8820d4..62c6280 100644 +index e66fc4b..f225e5b 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -31,6 +31,7 @@ @@ -89634,7 +89187,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 c94db1c..09c620f 100644 +index 9f7d585..6426811 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -348,6 +348,25 @@ config I2C_BCM2835 @@ -89664,7 +89217,7 @@ index c94db1c..09c620f 100644 tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile -index 18d18ff..7b9435a 100644 +index dd9a7f8..359bc30 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o @@ -90101,7 +89654,7 @@ index 0000000..f266f10 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig -index 60f2b41..6015c1e 100644 +index 213b5cb..cb20594 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -85,6 +85,14 @@ config SPI_BCM2835 @@ -90120,20 +89673,20 @@ index 60f2b41..6015c1e 100644 tristate "SPI controller driver for ADI Blackfin5xx" depends on BLACKFIN && !BF60x diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile -index bd79266..81b30d1 100644 +index 929c9f5..60871de 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o - obj-$(CONFIG_SPI_BFIN_V3) += spi-bfin-v3.o + obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o +obj-$(CONFIG_SPI_BCM2708) += spi-bcm2708.o obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o 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..06dd02f +index 0000000..b04a57d --- /dev/null +++ b/drivers/spi/spi-bcm2708.c @@ -0,0 +1,626 @@ @@ -90722,7 +90275,7 @@ index 0000000..06dd02f + bcm2708_wr(bs, SPI_CS, SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX); + spin_unlock_irq(&bs->lock); + -+ flush_work_sync(&bs->work); ++ flush_work(&bs->work); + + clk_disable(bs->clk); + clk_put(bs->clk); @@ -90767,10 +90320,10 @@ index 0000000..06dd02f 2.0.3 -From ed1fc584b74de29ea7f1239b92cd78e54e1fd482 Mon Sep 17 00:00:00 2001 +From 807ad336fb3a9c14bc6b08615f4f32603c89c48e Mon Sep 17 00:00:00 2001 From: cbeytas Date: Mon, 24 Jun 2013 00:05:40 -0400 -Subject: [PATCH 18/81] Perform I2C combined transactions when possible +Subject: [PATCH 19/69] Perform I2C combined transactions when possible Perform I2C combined transactions whenever possible, within the restrictions of the Broadcomm Serial Controller. @@ -90845,10 +90398,10 @@ index f266f10..8750634 100644 2.0.3 -From 534c1871b94c522d19c1a4992a6657806beacd09 Mon Sep 17 00:00:00 2001 +From 0fd73af06f60a6296e4ff5190c5f3eda88580b2f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 19/81] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 20/69] 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 @@ -90874,7 +90427,7 @@ Signed-off-by: Alex J Lennon 5 files changed, 114 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 62c6280..c8763c9 100644 +index f225e5b..16307ab 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -32,6 +32,7 @@ @@ -90938,7 +90491,7 @@ index 62c6280..c8763c9 100644 bcm_register_device(&bcm2708_systemtimer_device); bcm_register_device(&bcm2708_fb_device); bcm_register_device(&bcm2708_usb_device); -@@ -883,3 +910,5 @@ module_param(uart_clock, uint, 0644); +@@ -884,3 +911,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); @@ -91048,7 +90601,7 @@ index 1d111e5..61be2cd 100644 } diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h -index 734dab7..a3a64d8 100644 +index 56a49ba..881d728 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -171,6 +171,12 @@ struct w1_bus_master @@ -91123,17 +90676,17 @@ index 2820924..fd0550f 100644 2.0.3 -From 4d4b69d64dfc55517bdfcc80d78b83d71915dc80 Mon Sep 17 00:00:00 2001 +From 410dfdc7595b5cdd5d14d2085ca96cc1556d2dc3 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 12 Apr 2013 23:58:47 +0100 -Subject: [PATCH 23/81] config: add missing options from 3.6.y kernel +Subject: [PATCH 24/69] config: add missing options from 3.6.y kernel --- - arch/arm/configs/bcmrpi_defconfig | 755 ++++++++++++++++++++++++++++++++------ - 1 file changed, 649 insertions(+), 106 deletions(-) + arch/arm/configs/bcmrpi_defconfig | 757 ++++++++++++++++++++++++++++++++------ + 1 file changed, 651 insertions(+), 106 deletions(-) diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 31f5afaa..78d789c 100644 +index 31f5afaa..5b69e83 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -1,11 +1,17 @@ @@ -91500,7 +91053,7 @@ index 31f5afaa..78d789c 100644 CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m -@@ -89,35 +365,105 @@ CONFIG_BT_HCIVHCI=m +@@ -89,35 +365,106 @@ CONFIG_BT_HCIVHCI=m CONFIG_BT_MRVL=m CONFIG_BT_MRVL_SDIO=m CONFIG_BT_ATH3K=m @@ -91528,6 +91081,7 @@ index 31f5afaa..78d789c 100644 CONFIG_BLK_DEV_RAM=y CONFIG_CDROM_PKTCDVD=m -CONFIG_MISC_DEVICES=y ++CONFIG_EEPROM_AT24=m CONFIG_SCSI=y # CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=m @@ -91614,7 +91168,7 @@ index 31f5afaa..78d789c 100644 CONFIG_LIBERTAS_THINFIRM=m CONFIG_LIBERTAS_THINFIRM_USB=m CONFIG_AT76C50X_USB=m -@@ -125,14 +471,17 @@ CONFIG_USB_ZD1201=m +@@ -125,14 +472,17 @@ CONFIG_USB_ZD1201=m CONFIG_USB_NET_RNDIS_WLAN=m CONFIG_RTL8187=m CONFIG_MAC80211_HWSIM=m @@ -91634,7 +91188,7 @@ index 31f5afaa..78d789c 100644 CONFIG_LIBERTAS=m CONFIG_LIBERTAS_USB=m CONFIG_LIBERTAS_SDIO=m -@@ -142,57 +491,28 @@ CONFIG_RT2X00=m +@@ -142,57 +492,28 @@ CONFIG_RT2X00=m CONFIG_RT2500USB=m CONFIG_RT73USB=m CONFIG_RT2800USB=m @@ -91700,11 +91254,12 @@ index 31f5afaa..78d789c 100644 CONFIG_INPUT_ATI_REMOTE2=m CONFIG_INPUT_KEYSPAN_REMOTE=m CONFIG_INPUT_POWERMATE=m -@@ -207,26 +527,190 @@ CONFIG_SERIO_RAW=m +@@ -207,26 +528,191 @@ CONFIG_SERIO_RAW=m CONFIG_GAMEPORT=m CONFIG_GAMEPORT_NS558=m CONFIG_GAMEPORT_L4=m -CONFIG_VT_HW_CONSOLE_BINDING=y ++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_AMBA_PL011=y @@ -91895,7 +91450,7 @@ index 31f5afaa..78d789c 100644 CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set -@@ -249,10 +733,10 @@ CONFIG_SND_BCM2835=m +@@ -249,10 +735,10 @@ CONFIG_SND_BCM2835=m CONFIG_SND_USB_AUDIO=m CONFIG_SND_USB_UA101=m CONFIG_SND_USB_CAIAQ=m @@ -91908,7 +91463,7 @@ index 31f5afaa..78d789c 100644 CONFIG_HID_A4TECH=m CONFIG_HID_ACRUX=m CONFIG_HID_APPLE=m -@@ -283,7 +767,6 @@ CONFIG_HID_ORTEK=m +@@ -283,7 +769,6 @@ CONFIG_HID_ORTEK=m CONFIG_HID_PANTHERLORD=m CONFIG_HID_PETALYNX=m CONFIG_HID_PICOLCD=m @@ -91916,7 +91471,7 @@ index 31f5afaa..78d789c 100644 CONFIG_HID_ROCCAT=m CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m -@@ -292,15 +775,20 @@ CONFIG_HID_SUNPLUS=m +@@ -292,15 +777,20 @@ CONFIG_HID_SUNPLUS=m CONFIG_HID_GREENASIA=m CONFIG_HID_SMARTJOYPLUS=m CONFIG_HID_TOPSEED=m @@ -91937,7 +91492,7 @@ index 31f5afaa..78d789c 100644 CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m CONFIG_USB_STORAGE_DATAFAB=m -@@ -315,8 +803,6 @@ CONFIG_USB_STORAGE_ONETOUCH=m +@@ -315,8 +805,6 @@ CONFIG_USB_STORAGE_ONETOUCH=m CONFIG_USB_STORAGE_KARMA=m CONFIG_USB_STORAGE_CYPRESS_ATACB=m CONFIG_USB_STORAGE_ENE_UB6250=m @@ -91946,7 +91501,7 @@ index 31f5afaa..78d789c 100644 CONFIG_USB_MDC800=m CONFIG_USB_MICROTEK=m CONFIG_USB_SERIAL=m -@@ -331,12 +817,12 @@ CONFIG_USB_SERIAL_CP210X=m +@@ -331,12 +819,12 @@ CONFIG_USB_SERIAL_CP210X=m CONFIG_USB_SERIAL_CYPRESS_M8=m CONFIG_USB_SERIAL_EMPEG=m CONFIG_USB_SERIAL_FTDI_SIO=m @@ -91960,7 +91515,7 @@ index 31f5afaa..78d789c 100644 CONFIG_USB_SERIAL_GARMIN=m CONFIG_USB_SERIAL_IPW=m CONFIG_USB_SERIAL_IUU=m -@@ -345,18 +831,16 @@ CONFIG_USB_SERIAL_KEYSPAN=m +@@ -345,18 +833,16 @@ CONFIG_USB_SERIAL_KEYSPAN=m CONFIG_USB_SERIAL_KLSI=m CONFIG_USB_SERIAL_KOBIL_SCT=m CONFIG_USB_SERIAL_MCT_U232=m @@ -91980,7 +91535,7 @@ index 31f5afaa..78d789c 100644 CONFIG_USB_SERIAL_SIERRAWIRELESS=m CONFIG_USB_SERIAL_SYMBOL=m CONFIG_USB_SERIAL_TI=m -@@ -365,9 +849,11 @@ CONFIG_USB_SERIAL_XIRCOM=m +@@ -365,9 +851,11 @@ CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_OPTION=m CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_OPTICON=m @@ -91994,7 +91549,7 @@ index 31f5afaa..78d789c 100644 CONFIG_USB_SERIAL_DEBUG=m CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m -@@ -389,17 +875,74 @@ CONFIG_USB_TEST=m +@@ -389,17 +877,74 @@ CONFIG_USB_TEST=m CONFIG_USB_ISIGHTFW=m CONFIG_USB_YUREX=m CONFIG_MMC=y @@ -92074,7 +91629,7 @@ index 31f5afaa..78d789c 100644 # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y -@@ -422,6 +965,8 @@ CONFIG_BTRFS_FS=m +@@ -422,6 +967,8 @@ CONFIG_BTRFS_FS=m CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_FANOTIFY=y @@ -92083,7 +91638,7 @@ index 31f5afaa..78d789c 100644 CONFIG_AUTOFS4_FS=y CONFIG_FUSE_FS=m CONFIG_CUSE=m -@@ -437,28 +982,32 @@ CONFIG_MSDOS_FS=y +@@ -437,28 +984,32 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_NTFS_FS=m @@ -92120,7 +91675,7 @@ index 31f5afaa..78d789c 100644 CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=m -@@ -497,39 +1046,33 @@ CONFIG_NLS_ISO8859_14=m +@@ -497,39 +1048,33 @@ CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m @@ -92176,785 +91731,10 @@ index 31f5afaa..78d789c 100644 2.0.3 -From 82927414620788caff4074a3ea1023c470188839 Mon Sep 17 00:00:00 2001 -From: Harm Hanemaaijer -Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 24/81] 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 -console monochrome imageblit function used to draw console text is -suboptimal for common pixel depths such as 16bpp and 32bpp. The existing -code is quite general and can deal with several pixel depths. By creating -special case functions for 16bpp and 32bpp, by far the most common pixel -formats used on modern systems, a significant speed-up is attained -which can be readily felt on ARM-based devices like the Raspberry Pi -and the Allwinner platform, but should help any platform using the -fb layer. - -The special case functions allow constant folding, eliminating a number -of instructions including divide operations, and allow the use of an -unrolled loop, eliminating instructions with a variable shift size, -reducing source memory access instructions, and eliminating excessive -branching. These unrolled loops also allow much better code optimization -by the C compiler. The code that selects which optimized variant is used -is also simplified, eliminating integer divide instructions. - -The speed-up, measured by timing 'cat file.txt' in the console, varies -between 40% and 70%, when testing on the Raspberry Pi and Allwinner -ARM-based platforms, depending on font size and the pixel depth, with -the greater benefit for 32bpp. - -Signed-off-by: Harm Hanemaaijer ---- - drivers/video/fbdev/core/cfbimgblt.c | 152 +++++++++++++++++++++++++++++++++-- - 1 file changed, 147 insertions(+), 5 deletions(-) - -diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c -index a2bb276..436494f 100644 ---- 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 - * the native cpu endians. I also need to deal with MSB position in the word. -+ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013: -+ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are -+ * significantly faster than the previous implementation. -+ * - Simplify the fast/slow_imageblit selection code, avoiding integer -+ * divides. - */ - #include - #include -@@ -262,6 +267,133 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * - } - } - -+/* -+ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded -+ * into the code, main loop unrolled. -+ */ -+ -+static inline void fast_imageblit16(const struct fb_image *image, -+ struct fb_info *p, u8 __iomem * dst1, -+ u32 fgcolor, u32 bgcolor) -+{ -+ u32 fgx = fgcolor, bgx = bgcolor; -+ u32 spitch = (image->width + 7) / 8; -+ u32 end_mask, eorx; -+ const char *s = image->data, *src; -+ u32 __iomem *dst; -+ const u32 *tab = NULL; -+ int i, j, k; -+ -+ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; -+ -+ fgx <<= 16; -+ bgx <<= 16; -+ fgx |= fgcolor; -+ bgx |= bgcolor; -+ -+ eorx = fgx ^ bgx; -+ k = image->width / 2; -+ -+ for (i = image->height; i--;) { -+ dst = (u32 __iomem *) dst1; -+ src = s; -+ -+ j = k; -+ while (j >= 4) { -+ u8 bits = *src; -+ end_mask = tab[(bits >> 6) & 3]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[(bits >> 4) & 3]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[(bits >> 2) & 3]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[bits & 3]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ src++; -+ j -= 4; -+ } -+ if (j != 0) { -+ u8 bits = *src; -+ end_mask = tab[(bits >> 6) & 3]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ if (j >= 2) { -+ end_mask = tab[(bits >> 4) & 3]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ if (j == 3) { -+ end_mask = tab[(bits >> 2) & 3]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst); -+ } -+ } -+ } -+ dst1 += p->fix.line_length; -+ s += spitch; -+ } -+} -+ -+/* -+ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded -+ * into the code, main loop unrolled. -+ */ -+ -+static inline void fast_imageblit32(const struct fb_image *image, -+ struct fb_info *p, u8 __iomem * dst1, -+ u32 fgcolor, u32 bgcolor) -+{ -+ u32 fgx = fgcolor, bgx = bgcolor; -+ u32 spitch = (image->width + 7) / 8; -+ u32 end_mask, eorx; -+ const char *s = image->data, *src; -+ u32 __iomem *dst; -+ const u32 *tab = NULL; -+ int i, j, k; -+ -+ tab = cfb_tab32; -+ -+ eorx = fgx ^ bgx; -+ k = image->width; -+ -+ for (i = image->height; i--;) { -+ dst = (u32 __iomem *) dst1; -+ src = s; -+ -+ j = k; -+ while (j >= 8) { -+ u8 bits = *src; -+ end_mask = tab[(bits >> 7) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[(bits >> 6) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[(bits >> 5) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[(bits >> 4) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[(bits >> 3) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[(bits >> 2) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[(bits >> 1) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ end_mask = tab[bits & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ src++; -+ j -= 8; -+ } -+ if (j != 0) { -+ u32 bits = (u32) * src; -+ while (j > 1) { -+ end_mask = tab[(bits >> 7) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); -+ bits <<= 1; -+ j--; -+ } -+ end_mask = tab[(bits >> 7) & 1]; -+ FB_WRITEL((end_mask & eorx) ^ bgx, dst); -+ } -+ dst1 += p->fix.line_length; -+ s += spitch; -+ } -+} -+ - void cfb_imageblit(struct fb_info *p, const struct fb_image *image) - { - u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; -@@ -294,11 +426,21 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) - bgcolor = image->bg_color; - } - -- if (32 % bpp == 0 && !start_index && !pitch_index && -- ((width & (32/bpp-1)) == 0) && -- bpp >= 8 && bpp <= 32) -- fast_imageblit(image, p, dst1, fgcolor, bgcolor); -- else -+ if (!start_index && !pitch_index) { -+ if (bpp == 32) -+ fast_imageblit32(image, p, dst1, fgcolor, -+ bgcolor); -+ else if (bpp == 16 && (width & 1) == 0) -+ fast_imageblit16(image, p, dst1, fgcolor, -+ bgcolor); -+ else if (bpp == 8 && (width & 3) == 0) -+ fast_imageblit(image, p, dst1, fgcolor, -+ bgcolor); -+ else -+ slow_imageblit(image, p, dst1, fgcolor, -+ bgcolor, -+ start_index, pitch_index); -+ } else - slow_imageblit(image, p, dst1, fgcolor, bgcolor, - start_index, pitch_index); - } else --- -2.0.3 - - -From ade6c7997f76a49bfc9ea4a4ff275e2f7bf27315 Mon Sep 17 00:00:00 2001 -From: Siarhei Siamashka -Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 25/81] fbdev: add FBIOCOPYAREA ioctl - -Based on the patch authored by Ali Gholami Rudi at - https://lkml.org/lkml/2009/7/13/153 - -Provide an ioctl for userspace applications, but only if this operation -is hardware accelerated (otherwide it does not make any sense). - -Signed-off-by: Siarhei Siamashka ---- - drivers/video/fbdev/core/fbmem.c | 30 ++++++++++++++++++++++++++++++ - include/uapi/linux/fb.h | 5 +++++ - 2 files changed, 35 insertions(+) - -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); - -+static int fb_copyarea_user(struct fb_info *info, -+ struct fb_copyarea *copy) -+{ -+ int ret = 0; -+ if (!lock_fb_info(info)) -+ return -ENODEV; -+ if (copy->dx + copy->width > info->var.xres || -+ copy->sx + copy->width > info->var.xres || -+ copy->dy + copy->height > info->var.yres || -+ copy->sy + copy->height > info->var.yres) { -+ ret = -EINVAL; -+ goto out; -+ } -+ info->fbops->fb_copyarea(info, copy); -+out: -+ unlock_fb_info(info); -+ return ret; -+} -+ - static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) - { -@@ -1093,6 +1112,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, - struct fb_cmap cmap_from; - struct fb_cmap_user cmap; - struct fb_event event; -+ struct fb_copyarea copy; - void __user *argp = (void __user *)arg; - long ret = 0; - -@@ -1210,6 +1230,15 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, - unlock_fb_info(info); - console_unlock(); - break; -+ case FBIOCOPYAREA: -+ if (info->flags & FBINFO_HWACCEL_COPYAREA) { -+ /* only provide this ioctl if it is accelerated */ -+ if (copy_from_user(©, argp, sizeof(copy))) -+ return -EFAULT; -+ ret = fb_copyarea_user(info, ©); -+ break; -+ } -+ /* fall through */ - default: - if (!lock_fb_info(info)) - return -ENODEV; -@@ -1364,6 +1393,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, - case FBIOPAN_DISPLAY: - case FBIOGET_CON2FBMAP: - case FBIOPUT_CON2FBMAP: -+ case FBIOCOPYAREA: - arg = (unsigned long) compat_ptr(arg); - case FBIOBLANK: - ret = do_fb_ioctl(info, cmd, arg); -diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h -index fb795c3..fa72af0 100644 ---- a/include/uapi/linux/fb.h -+++ b/include/uapi/linux/fb.h -@@ -34,6 +34,11 @@ - #define FBIOPUT_MODEINFO 0x4617 - #define FBIOGET_DISPINFO 0x4618 - #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) -+/* -+ * HACK: use 'z' in order not to clash with any other ioctl numbers which might -+ * be concurrently added to the mainline kernel -+ */ -+#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea) - - #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ - #define FB_TYPE_PLANES 1 /* Non interleaved planes */ --- -2.0.3 - - -From 795dc56ad12e1e0b3f5da96f3986cc480146f406 Mon Sep 17 00:00:00 2001 -From: Siarhei Siamashka -Date: Mon, 17 Jun 2013 16:00:25 +0300 -Subject: [PATCH 26/81] 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 -settings for better performance. - -For now busylooping only. IRQ support might be added later. -With non-overclocked Raspberry Pi, the performance is ~360 MB/s -for simple copy or ~260 MB/s for two-pass copy (used when dragging -windows to the right). - -In the case of using DMA channel 0, the performance improves -to ~440 MB/s. - -For comparison, VFP optimized CPU copy can only do ~114 MB/s in -the same conditions (hindered by reading uncached source buffer). - -Signed-off-by: Siarhei Siamashka - -bcm2708_fb: report number of dma copies - -Add a counter (exported via debugfs) reporting the -number of dma copies that the framebuffer driver -has done, in order to help evaluate different -optimization strategies. - -Signed-off-by: Luke Diamand - -bcm2708_fb: use IRQ for DMA copies - -The copyarea ioctl() uses DMA to speed things along. This -was busy-waiting for completion. This change supports using -an interrupt instead for larger transfers. For small -transfers, busy-waiting is still likely to be faster. - -Signed-off-by: Luke Diamand ---- - arch/arm/mach-bcm2708/dma.c | 8 + - arch/arm/mach-bcm2708/include/mach/dma.h | 2 + - 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 -index 51d147a..1da2413 100644 ---- a/arch/arm/mach-bcm2708/dma.c -+++ b/arch/arm/mach-bcm2708/dma.c -@@ -83,6 +83,14 @@ extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) - - EXPORT_SYMBOL_GPL(bcm_dma_start); - -+extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) -+{ -+ dsb(); -+ -+ return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; -+} -+EXPORT_SYMBOL_GPL(bcm_dma_is_busy); -+ - /* Complete an ongoing DMA (assuming its results are to be ignored) - Does nothing if there is no DMA in progress. - This routine waits for the current AXI transfer to complete before -diff --git a/arch/arm/mach-bcm2708/include/mach/dma.h b/arch/arm/mach-bcm2708/include/mach/dma.h -index ac7a4a0..6d2f9a0 100644 ---- a/arch/arm/mach-bcm2708/include/mach/dma.h -+++ b/arch/arm/mach-bcm2708/include/mach/dma.h -@@ -62,11 +62,13 @@ struct bcm2708_dma_cb { - unsigned long next; - unsigned long pad[2]; - }; -+struct scatterlist; - - extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); - extern void bcm_dma_start(void __iomem *dma_chan_base, - dma_addr_t control_block); - extern void bcm_dma_wait_idle(void __iomem *dma_chan_base); -+extern bool bcm_dma_is_busy(void __iomem *dma_chan_base); - 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/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c -index 54cd760..798eb52 100644 ---- a/drivers/video/fbdev/bcm2708_fb.c -+++ b/drivers/video/fbdev/bcm2708_fb.c -@@ -21,13 +21,16 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - #include - #include -+#include - -+#include - #include - #include - -@@ -51,6 +54,10 @@ static int fbheight = 480; /* module parameter */ - static int fbdepth = 16; /* module parameter */ - static int fbswap = 0; /* module parameter */ - -+static u32 dma_busy_wait_threshold = 1<<15; -+module_param(dma_busy_wait_threshold, int, 0644); -+MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area"); -+ - /* this data structure describes each frame buffer device we find */ - - struct fbinfo_s { -@@ -62,16 +69,73 @@ struct fbinfo_s { - u16 cmap[256]; - }; - -+struct bcm2708_fb_stats { -+ struct debugfs_regset32 regset; -+ u32 dma_copies; -+ u32 dma_irqs; -+}; -+ - struct bcm2708_fb { - struct fb_info fb; - struct platform_device *dev; - struct fbinfo_s *info; - dma_addr_t dma; - u32 cmap[16]; -+ int dma_chan; -+ int dma_irq; -+ void __iomem *dma_chan_base; -+ void *cb_base; /* DMA control blocks */ -+ dma_addr_t cb_handle; -+ struct dentry *debugfs_dir; -+ wait_queue_head_t dma_waitq; -+ struct bcm2708_fb_stats stats; - }; - - #define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb) - -+static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb) -+{ -+ debugfs_remove_recursive(fb->debugfs_dir); -+ fb->debugfs_dir = NULL; -+} -+ -+static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb) -+{ -+ static struct debugfs_reg32 stats_registers[] = { -+ { -+ "dma_copies", -+ offsetof(struct bcm2708_fb_stats, dma_copies) -+ }, -+ { -+ "dma_irqs", -+ offsetof(struct bcm2708_fb_stats, dma_irqs) -+ }, -+ }; -+ -+ fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL); -+ if (!fb->debugfs_dir) { -+ pr_warn("%s: could not create debugfs entry\n", -+ __func__); -+ return -EFAULT; -+ } -+ -+ fb->stats.regset.regs = stats_registers; -+ fb->stats.regset.nregs = ARRAY_SIZE(stats_registers); -+ fb->stats.regset.base = &fb->stats; -+ -+ if (!debugfs_create_regset32( -+ "stats", 0444, fb->debugfs_dir, &fb->stats.regset)) { -+ pr_warn("%s: could not create statistics registers\n", -+ __func__); -+ goto fail; -+ } -+ return 0; -+ -+fail: -+ bcm2708_fb_debugfs_deinit(fb); -+ return -EFAULT; -+} -+ - static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var) - { - int ret = 0; -@@ -322,11 +386,148 @@ static void bcm2708_fb_fillrect(struct fb_info *info, - cfb_fillrect(info, rect); - } - -+/* A helper function for configuring dma control block */ -+static void set_dma_cb(struct bcm2708_dma_cb *cb, -+ int burst_size, -+ dma_addr_t dst, -+ int dst_stride, -+ dma_addr_t src, -+ int src_stride, -+ int w, -+ int h) -+{ -+ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH | -+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH | -+ BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE; -+ cb->dst = dst; -+ cb->src = src; -+ /* -+ * This is not really obvious from the DMA documentation, -+ * but the top 16 bits must be programmmed to "height -1" -+ * and not "height" in 2D mode. -+ */ -+ cb->length = ((h - 1) << 16) | w; -+ cb->stride = ((dst_stride - w) << 16) | (u16)(src_stride - w); -+ cb->pad[0] = 0; -+ cb->pad[1] = 0; -+} -+ - static void bcm2708_fb_copyarea(struct fb_info *info, - const struct fb_copyarea *region) - { -- /*print_debug("bcm2708_fb_copyarea\n"); */ -- cfb_copyarea(info, region); -+ struct bcm2708_fb *fb = to_bcm2708(info); -+ struct bcm2708_dma_cb *cb = fb->cb_base; -+ int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; -+ /* Channel 0 supports larger bursts and is a bit faster */ -+ int burst_size = (fb->dma_chan == 0) ? 8 : 2; -+ int pixels = region->width * region->height; -+ -+ /* Fallback to cfb_copyarea() if we don't like something */ -+ if (bytes_per_pixel > 4 || -+ info->var.xres * info->var.yres > 1920 * 1200 || -+ region->width <= 0 || region->width > info->var.xres || -+ region->height <= 0 || region->height > info->var.yres || -+ region->sx < 0 || region->sx >= info->var.xres || -+ region->sy < 0 || region->sy >= info->var.yres || -+ region->dx < 0 || region->dx >= info->var.xres || -+ region->dy < 0 || region->dy >= info->var.yres || -+ region->sx + region->width > info->var.xres || -+ region->dx + region->width > info->var.xres || -+ region->sy + region->height > info->var.yres || -+ region->dy + region->height > info->var.yres) { -+ cfb_copyarea(info, region); -+ return; -+ } -+ -+ if (region->dy == region->sy && region->dx > region->sx) { -+ /* -+ * A difficult case of overlapped copy. Because DMA can't -+ * copy individual scanlines in backwards direction, we need -+ * two-pass processing. We do it by programming a chain of dma -+ * control blocks in the first 16K part of the buffer and use -+ * the remaining 48K as the intermediate temporary scratch -+ * buffer. The buffer size is sufficient to handle up to -+ * 1920x1200 resolution at 32bpp pixel depth. -+ */ -+ int y; -+ dma_addr_t control_block_pa = fb->cb_handle; -+ dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024; -+ int scanline_size = bytes_per_pixel * region->width; -+ int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size; -+ -+ for (y = 0; y < region->height; y += scanlines_per_cb) { -+ dma_addr_t src = -+ fb->fb.fix.smem_start + -+ bytes_per_pixel * region->sx + -+ (region->sy + y) * fb->fb.fix.line_length; -+ dma_addr_t dst = -+ fb->fb.fix.smem_start + -+ bytes_per_pixel * region->dx + -+ (region->dy + y) * fb->fb.fix.line_length; -+ -+ if (region->height - y < scanlines_per_cb) -+ scanlines_per_cb = region->height - y; -+ -+ set_dma_cb(cb, burst_size, scratchbuf, scanline_size, -+ src, fb->fb.fix.line_length, -+ scanline_size, scanlines_per_cb); -+ control_block_pa += sizeof(struct bcm2708_dma_cb); -+ cb->next = control_block_pa; -+ cb++; -+ -+ set_dma_cb(cb, burst_size, dst, fb->fb.fix.line_length, -+ scratchbuf, scanline_size, -+ scanline_size, scanlines_per_cb); -+ control_block_pa += sizeof(struct bcm2708_dma_cb); -+ cb->next = control_block_pa; -+ cb++; -+ } -+ /* move the pointer back to the last dma control block */ -+ cb--; -+ } else { -+ /* A single dma control block is enough. */ -+ int sy, dy, stride; -+ if (region->dy <= region->sy) { -+ /* processing from top to bottom */ -+ dy = region->dy; -+ sy = region->sy; -+ stride = fb->fb.fix.line_length; -+ } else { -+ /* processing from bottom to top */ -+ dy = region->dy + region->height - 1; -+ sy = region->sy + region->height - 1; -+ stride = -fb->fb.fix.line_length; -+ } -+ set_dma_cb(cb, burst_size, -+ fb->fb.fix.smem_start + dy * fb->fb.fix.line_length + -+ bytes_per_pixel * region->dx, -+ stride, -+ fb->fb.fix.smem_start + sy * fb->fb.fix.line_length + -+ bytes_per_pixel * region->sx, -+ stride, -+ region->width * bytes_per_pixel, -+ region->height); -+ } -+ -+ /* end of dma control blocks chain */ -+ cb->next = 0; -+ -+ -+ if (pixels < dma_busy_wait_threshold) { -+ bcm_dma_start(fb->dma_chan_base, fb->cb_handle); -+ bcm_dma_wait_idle(fb->dma_chan_base); -+ } else { -+ void __iomem *dma_chan = fb->dma_chan_base; -+ cb->info |= BCM2708_DMA_INT_EN; -+ bcm_dma_start(fb->dma_chan_base, fb->cb_handle); -+ while (bcm_dma_is_busy(dma_chan)) { -+ wait_event_interruptible( -+ fb->dma_waitq, -+ !bcm_dma_is_busy(dma_chan)); -+ } -+ fb->stats.dma_irqs++; -+ } -+ fb->stats.dma_copies++; - } - - static void bcm2708_fb_imageblit(struct fb_info *info, -@@ -336,6 +537,24 @@ static void bcm2708_fb_imageblit(struct fb_info *info, - cfb_imageblit(info, image); - } - -+static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt) -+{ -+ struct bcm2708_fb *fb = cxt; -+ -+ /* FIXME: should read status register to check if this is -+ * actually interrupting us or not, in case this interrupt -+ * ever becomes shared amongst several DMA channels -+ * -+ * readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_IRQ; -+ */ -+ -+ /* acknowledge the interrupt */ -+ writel(BCM2708_DMA_INT, fb->dma_chan_base + BCM2708_DMA_CS); -+ -+ wake_up(&fb->dma_waitq); -+ return IRQ_HANDLED; -+} -+ - static struct fb_ops bcm2708_fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = bcm2708_fb_check_var, -@@ -365,7 +584,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb) - fb->dma = dma; - } - fb->fb.fbops = &bcm2708_fb_ops; -- fb->fb.flags = FBINFO_FLAG_DEFAULT; -+ fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA; - fb->fb.pseudo_palette = fb->cmap; - - strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id)); -@@ -396,6 +615,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb) - fb->fb.monspecs.dclkmax = 100000000; - - bcm2708_fb_set_bitfields(&fb->fb.var); -+ init_waitqueue_head(&fb->dma_waitq); - - /* - * Allocate colourmap. -@@ -421,14 +641,45 @@ static int bcm2708_fb_probe(struct platform_device *dev) - struct bcm2708_fb *fb; - int ret; - -- fb = kmalloc(sizeof(struct bcm2708_fb), GFP_KERNEL); -+ fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL); - if (!fb) { - dev_err(&dev->dev, - "could not allocate new bcm2708_fb struct\n"); - ret = -ENOMEM; - goto free_region; - } -- memset(fb, 0, sizeof(struct bcm2708_fb)); -+ -+ bcm2708_fb_debugfs_init(fb); -+ -+ fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K, -+ &fb->cb_handle, GFP_KERNEL); -+ if (!fb->cb_base) { -+ dev_err(&dev->dev, "cannot allocate DMA CBs\n"); -+ ret = -ENOMEM; -+ goto free_fb; -+ } -+ -+ pr_info("BCM2708FB: allocated DMA memory %08x\n", -+ fb->cb_handle); -+ -+ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK, -+ &fb->dma_chan_base, &fb->dma_irq); -+ if (ret < 0) { -+ dev_err(&dev->dev, "couldn't allocate a DMA channel\n"); -+ goto free_cb; -+ } -+ fb->dma_chan = ret; -+ -+ ret = request_irq(fb->dma_irq, bcm2708_fb_dma_irq, -+ 0, "bcm2708_fb dma", fb); -+ if (ret) { -+ pr_err("%s: failed to request DMA irq\n", __func__); -+ goto free_dma_chan; -+ } -+ -+ -+ pr_info("BCM2708FB: allocated DMA channel %d @ %p\n", -+ fb->dma_chan, fb->dma_chan_base); - - fb->dev = dev; - -@@ -438,6 +689,11 @@ static int bcm2708_fb_probe(struct platform_device *dev) - goto out; - } - -+free_dma_chan: -+ bcm_dma_chan_free(fb->dma_chan); -+free_cb: -+ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle); -+free_fb: - kfree(fb); - free_region: - dev_err(&dev->dev, "probe failed, err %d\n", ret); -@@ -455,8 +711,15 @@ static int bcm2708_fb_remove(struct platform_device *dev) - iounmap(fb->fb.screen_base); - unregister_framebuffer(&fb->fb); - -+ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle); -+ bcm_dma_chan_free(fb->dma_chan); -+ - dma_free_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), (void *)fb->info, - fb->dma); -+ bcm2708_fb_debugfs_deinit(fb); -+ -+ free_irq(fb->dma_irq, fb); -+ - kfree(fb); - - return 0; --- -2.0.3 - - -From 40fcc4794c417a1ff7345fb889fbe53a62435f5d Mon Sep 17 00:00:00 2001 +From bbd02eefcab6de94a76ff20ae8f41979a224264f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 27/81] config: Enable CONFIG_MEMCG, but leave it disabled (due +Subject: [PATCH 25/69] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -92964,7 +91744,7 @@ Subject: [PATCH 27/81] config: Enable CONFIG_MEMCG, but leave it disabled (due 3 files changed, 25 insertions(+) diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 78d789c..e89e430 100644 +index 5b69e83..11c6f8f 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -18,6 +18,7 @@ CONFIG_CGROUP_FREEZER=y @@ -92976,10 +91756,10 @@ index 78d789c..e89e430 100644 CONFIG_NAMESPACES=y CONFIG_SCHED_AUTOGROUP=y diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index 073226b..e787ee2 100644 +index 70776ae..4662d09 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c -@@ -4671,6 +4671,29 @@ static int __init cgroup_disable(char *str) +@@ -5205,6 +5205,29 @@ static int __init cgroup_disable(char *str) } __setup("cgroup_disable=", cgroup_disable); @@ -93007,13 +91787,13 @@ index 073226b..e787ee2 100644 +__setup("cgroup_enable=", cgroup_enable); + /** - * css_tryget_from_dir - get corresponding css from the dentry of a cgroup dir + * css_tryget_online_from_dir - get corresponding css from a cgroup dentry * @dentry: directory dentry of interest diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 67c927a..6512641 100644 +index 1f14a43..403173e 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -7158,6 +7158,7 @@ struct cgroup_subsys memory_cgrp_subsys = { +@@ -7029,6 +7029,7 @@ struct cgroup_subsys memory_cgrp_subsys = { .bind = mem_cgroup_bind, .base_cftypes = mem_cgroup_files, .early_init = 0, @@ -93025,10 +91805,10 @@ index 67c927a..6512641 100644 2.0.3 -From 7896e6f1a7052b79e8acd445f8db213a71a4412c Mon Sep 17 00:00:00 2001 +From fcdb10ea333e0f0945f9bbad6ea0f660b74000b6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:46:42 +0100 -Subject: [PATCH 28/81] Add FIQ patch to dwc_otg driver. Enable with +Subject: [PATCH 26/69] 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 @@ -93311,10 +92091,10 @@ incarnations. create mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 8c3505f..ac5410d 100644 +index cb53c45..d0c3229 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -399,6 +399,7 @@ config ARCH_BCM2708 +@@ -388,6 +388,7 @@ config ARCH_BCM2708 select ARM_ERRATA_411920 select MACH_BCM2708 select VC4 @@ -93365,7 +92145,7 @@ index 207f9d6..5233d54 100644 + 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 +index efade23..d4c5333 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) @@ -93408,7 +92188,7 @@ index da18725..274aa30 100644 return 0; } diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index c8763c9..320b5d2 100644 +index 16307ab..d0dfac5 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[] = { @@ -96350,10 +95130,10 @@ index 1b1f83c..c8590b5 100644 2.0.3 -From 974c55e0b59c8f6f4d9ded8d3377e33302bf2864 Mon Sep 17 00:00:00 2001 +From 8c8c4ef61da26e49e22db4625333aef308dfd1dc Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 19 Mar 2014 12:58:23 +0000 -Subject: [PATCH 29/81] dwc_otg: fiq_fsm: Base commit for driver rewrite +Subject: [PATCH 27/69] dwc_otg: fiq_fsm: Base commit for driver rewrite This commit removes the previous FIQ fixes entirely and adds fiq_fsm. @@ -96474,7 +95254,7 @@ fiq_fsm: Enable by default 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 320b5d2..ef0935f 100644 +index d0dfac5..a6eb08e 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[] = { @@ -101252,10 +100032,10 @@ index 5d310df..4b32941 100644 2.0.3 -From b4c6788087cd8b5566769df99caca4b272b4f54f Mon Sep 17 00:00:00 2001 +From 198112683018b1c563861d89649ef42bfa04eda9 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 30/81] bcm2835: add v4l2 camera device +Subject: [PATCH 28/69] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -101367,10 +100147,10 @@ index 0000000..c585a8f + +$ v4l2-ctl --list-formats diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 20f1655..a63b88b 100644 +index 8108c69..76c70d6 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig -@@ -118,6 +118,7 @@ config VIDEO_S3C_CAMIF +@@ -120,6 +120,7 @@ config VIDEO_S3C_CAMIF source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" @@ -107243,10 +106023,10 @@ index 0000000..9d1d11e 2.0.3 -From 7cc01d34940d07f55ccace3f27532c1e18704f86 Mon Sep 17 00:00:00 2001 +From f9a983d9320bdc8b7d94fdedd59a015456dea8e2 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 10:58:01 +0000 -Subject: [PATCH 31/81] V4L2: Fixes from 6by9 +Subject: [PATCH 29/69] V4L2: Fixes from 6by9 V4L2: Fix EV values. Add manual shutter speed control @@ -107476,10 +106256,10 @@ Signed-off-by: Dave Stevenson 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 +index 11c6f8f..0c58172 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -694,6 +694,9 @@ CONFIG_DVB_B2C2_FLEXCOP_USB=m +@@ -696,6 +696,9 @@ CONFIG_DVB_B2C2_FLEXCOP_USB=m CONFIG_VIDEO_EM28XX=m CONFIG_VIDEO_EM28XX_ALSA=m CONFIG_VIDEO_EM28XX_DVB=m @@ -109621,484 +108401,10 @@ index a06fb44..76f249e 100644 2.0.3 -From 6c669caef8625f9430ad0d5233cf23101d5b598f Mon Sep 17 00:00:00 2001 -From: Julian Scheel -Date: Wed, 19 Feb 2014 16:06:59 +0100 -Subject: [PATCH 32/81] 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 -driver extension an appropriate card config is required to make alsa-lib -support the AES parameters for this device. ---- - sound/arm/bcm2835-ctl.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ - sound/arm/bcm2835-pcm.c | 128 +++++++++++++++++++++++++++++++++++++++++------- - sound/arm/bcm2835.c | 9 +++- - sound/arm/bcm2835.h | 9 ++++ - 4 files changed, 250 insertions(+), 19 deletions(-) - -diff --git a/sound/arm/bcm2835-ctl.c b/sound/arm/bcm2835-ctl.c -index 8c5334a..aad905f 100755 ---- a/sound/arm/bcm2835-ctl.c -+++ b/sound/arm/bcm2835-ctl.c -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - - #include "bcm2835.h" - -@@ -183,6 +184,122 @@ static struct snd_kcontrol_new snd_bcm2835_ctl[] = { - }, - }; - -+static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; -+ uinfo->count = 1; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); -+ int i; -+ -+ for (i = 0; i < 4; i++) -+ ucontrol->value.iec958.status[i] = -+ (chip->spdif_status >> (i * 8)) && 0xff; -+ -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); -+ unsigned int val = 0; -+ int i, change; -+ -+ for (i = 0; i < 4; i++) -+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); -+ -+ change = val != chip->spdif_status; -+ chip->spdif_status = val; -+ -+ return change; -+} -+ -+static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; -+ uinfo->count = 1; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ /* bcm2835 supports only consumer mode and sets all other format flags -+ * automatically. So the only thing left is signalling non-audio -+ * content */ -+ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; -+ uinfo->count = 1; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); -+ int i; -+ -+ for (i = 0; i < 4; i++) -+ ucontrol->value.iec958.status[i] = -+ (chip->spdif_status >> (i * 8)) & 0xff; -+ return 0; -+} -+ -+static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); -+ unsigned int val = 0; -+ int i, change; -+ -+ for (i = 0; i < 4; i++) -+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); -+ change = val != chip->spdif_status; -+ chip->spdif_status = val; -+ -+ return change; -+} -+ -+static struct snd_kcontrol_new snd_bcm2835_spdif[] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), -+ .info = snd_bcm2835_spdif_default_info, -+ .get = snd_bcm2835_spdif_default_get, -+ .put = snd_bcm2835_spdif_default_put -+ }, -+ { -+ .access = SNDRV_CTL_ELEM_ACCESS_READ, -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), -+ .info = snd_bcm2835_spdif_mask_info, -+ .get = snd_bcm2835_spdif_mask_get, -+ }, -+ { -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | -+ SNDRV_CTL_ELEM_ACCESS_INACTIVE, -+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, -+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), -+ .info = snd_bcm2835_spdif_stream_info, -+ .get = snd_bcm2835_spdif_stream_get, -+ .put = snd_bcm2835_spdif_stream_put, -+ }, -+}; -+ - int snd_bcm2835_new_ctl(bcm2835_chip_t * chip) - { - int err; -@@ -196,5 +313,11 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t * chip) - if (err < 0) - return err; - } -+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) { -+ err = snd_ctl_add(chip->card, -+ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip)); -+ if (err < 0) -+ return err; -+ } - return 0; - } -diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c -index b4084bb..ebd3f62 100755 ---- a/sound/arm/bcm2835-pcm.c -+++ b/sound/arm/bcm2835-pcm.c -@@ -15,6 +15,8 @@ - #include - #include - -+#include -+ - #include "bcm2835.h" - - /* hardware definition */ -@@ -34,6 +36,23 @@ static struct snd_pcm_hardware snd_bcm2835_playback_hw = { - .periods_max = 128, - }; - -+static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | -+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), -+ .formats = SNDRV_PCM_FMTBIT_S16_LE, -+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 | -+ SNDRV_PCM_RATE_48000, -+ .rate_min = 44100, -+ .rate_max = 48000, -+ .channels_min = 2, -+ .channels_max = 2, -+ .buffer_bytes_max = 128 * 1024, -+ .period_bytes_min = 1 * 1024, -+ .period_bytes_max = 128 * 1024, -+ .periods_min = 1, -+ .periods_max = 128, -+}; -+ - static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime) - { - audio_info("Freeing up alsa stream here ..\n"); -@@ -89,7 +108,8 @@ static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id) - } - - /* open callback */ --static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) -+static int snd_bcm2835_playback_open_generic( -+ struct snd_pcm_substream *substream, int spdif) - { - bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; -@@ -102,6 +122,11 @@ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) - audio_info("Alsa open (%d)\n", substream->number); - idx = substream->number; - -+ if (spdif && chip->opened != 0) -+ return -EBUSY; -+ else if (!spdif && (chip->opened & (1 << idx))) -+ return -EBUSY; -+ - if (idx > MAX_SUBSTREAMS) { - audio_error - ("substream(%d) device doesn't exist max(%d) substreams allowed\n", -@@ -143,13 +168,20 @@ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) - } - runtime->private_data = alsa_stream; - runtime->private_free = snd_bcm2835_playback_free; -- runtime->hw = snd_bcm2835_playback_hw; -+ if (spdif) { -+ runtime->hw = snd_bcm2835_playback_spdif_hw; -+ } else { -+ /* clear spdif status, as we are not in spdif mode */ -+ chip->spdif_status = 0; -+ runtime->hw = snd_bcm2835_playback_hw; -+ } - /* minimum 16 bytes alignment (for vchiq bulk transfers) */ - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - 16); - - chip->alsa_stream[idx] = alsa_stream; - -+ chip->opened |= (1 << idx); - alsa_stream->open = 1; - alsa_stream->draining = 1; - -@@ -159,6 +191,16 @@ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) - return err; - } - -+static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) -+{ -+ return snd_bcm2835_playback_open_generic(substream, 0); -+} -+ -+static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream) -+{ -+ return snd_bcm2835_playback_open_generic(substream, 1); -+} -+ - /* close callback */ - static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) - { -@@ -166,6 +208,7 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) - - struct snd_pcm_runtime *runtime = substream->runtime; - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); - - audio_info(" .. IN\n"); - audio_info("Alsa close\n"); -@@ -196,6 +239,8 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) - * runtime->private_free callback we registered in *_open above - */ - -+ chip->opened &= ~(1 << substream->number); -+ - audio_info(" .. OUT\n"); - - return 0; -@@ -205,10 +250,9 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) - static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) - { -- int err; - struct snd_pcm_runtime *runtime = substream->runtime; -- bcm2835_alsa_stream_t *alsa_stream = -- (bcm2835_alsa_stream_t *) runtime->private_data; -+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ int err; - - audio_info(" .. IN\n"); - -@@ -219,19 +263,9 @@ static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream, - return err; - } - -- err = bcm2835_audio_set_params(alsa_stream, params_channels(params), -- params_rate(params), -- snd_pcm_format_width(params_format -- (params))); -- if (err < 0) { -- audio_error(" error setting hw params\n"); -- } -- -- bcm2835_audio_setup(alsa_stream); -- -- /* in preparation of the stream, set the controls (volume level) of the stream */ -- bcm2835_audio_set_ctls(alsa_stream->chip); -- -+ alsa_stream->channels = params_channels(params); -+ alsa_stream->params_rate = params_rate(params); -+ alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params)); - audio_info(" .. OUT\n"); - - return err; -@@ -247,11 +281,35 @@ static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream) - /* prepare callback */ - static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) - { -+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -+ int channels; -+ int err; - - audio_info(" .. IN\n"); - -+ /* notify the vchiq that it should enter spdif passthrough mode by -+ * setting channels=0 (see -+ * https://github.com/raspberrypi/linux/issues/528) */ -+ if (chip->spdif_status & IEC958_AES0_NONAUDIO) -+ channels = 0; -+ else -+ channels = alsa_stream->channels; -+ -+ err = bcm2835_audio_set_params(alsa_stream, channels, -+ alsa_stream->params_rate, -+ alsa_stream->pcm_format_width); -+ if (err < 0) { -+ audio_error(" error setting hw params\n"); -+ } -+ -+ bcm2835_audio_setup(alsa_stream); -+ -+ /* in preparation of the stream, set the controls (volume level) of the stream */ -+ bcm2835_audio_set_ctls(alsa_stream->chip); -+ -+ - memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); - - alsa_stream->pcm_indirect.hw_buffer_size = -@@ -392,6 +450,18 @@ static struct snd_pcm_ops snd_bcm2835_playback_ops = { - .ack = snd_bcm2835_pcm_ack, - }; - -+static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { -+ .open = snd_bcm2835_playback_spdif_open, -+ .close = snd_bcm2835_playback_close, -+ .ioctl = snd_bcm2835_pcm_lib_ioctl, -+ .hw_params = snd_bcm2835_pcm_hw_params, -+ .hw_free = snd_bcm2835_pcm_hw_free, -+ .prepare = snd_bcm2835_pcm_prepare, -+ .trigger = snd_bcm2835_pcm_trigger, -+ .pointer = snd_bcm2835_pcm_pointer, -+ .ack = snd_bcm2835_pcm_ack, -+}; -+ - /* create a pcm device */ - int snd_bcm2835_new_pcm(bcm2835_chip_t * chip) - { -@@ -424,3 +494,25 @@ int snd_bcm2835_new_pcm(bcm2835_chip_t * chip) - - return 0; - } -+ -+int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip) -+{ -+ struct snd_pcm *pcm; -+ int err; -+ -+ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm); -+ if (err < 0) -+ return err; -+ -+ pcm->private_data = chip; -+ strcpy(pcm->name, "bcm2835 IEC958/HDMI"); -+ chip->pcm_spdif = pcm; -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, -+ &snd_bcm2835_playback_spdif_ops); -+ -+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, -+ snd_dma_continuous_data (GFP_KERNEL), -+ 64 * 1024, 64 * 1024); -+ -+ return 0; -+} -diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c -index e2047a7..4136760 100755 ---- a/sound/arm/bcm2835.c -+++ b/sound/arm/bcm2835.c -@@ -104,7 +104,7 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - goto out; - - snd_card_set_dev(g_card, &pdev->dev); -- strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver"); -+ strcpy(g_card->driver, "bcm2835"); - strcpy(g_card->shortname, "bcm2835 ALSA"); - sprintf(g_card->longname, "%s", g_card->shortname); - -@@ -121,6 +121,12 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - goto out_bcm2835_new_pcm; - } - -+ err = snd_bcm2835_new_spdif_pcm(chip); -+ if (err < 0) { -+ dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n"); -+ goto out_bcm2835_new_spdif; -+ } -+ - err = snd_bcm2835_new_ctl(chip); - if (err < 0) { - dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n"); -@@ -156,6 +162,7 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - - out_card_register: - out_bcm2835_new_ctl: -+out_bcm2835_new_spdif: - out_bcm2835_new_pcm: - out_bcm2835_create: - BUG_ON(!g_card); -diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h -index 36afee3..8c2fe26 100755 ---- a/sound/arm/bcm2835.h -+++ b/sound/arm/bcm2835.h -@@ -97,6 +97,7 @@ typedef enum { - typedef struct bcm2835_chip { - struct snd_card *card; - struct snd_pcm *pcm; -+ struct snd_pcm *pcm_spdif; - /* Bitmat for valid reg_base and irq numbers */ - uint32_t avail_substreams; - struct platform_device *pdev[MAX_SUBSTREAMS]; -@@ -106,6 +107,9 @@ typedef struct bcm2835_chip { - int old_volume; /* stores the volume value whist muted */ - int dest; - int mute; -+ -+ unsigned int opened; -+ unsigned int spdif_status; - } bcm2835_chip_t; - - typedef struct bcm2835_alsa_stream { -@@ -123,6 +127,10 @@ typedef struct bcm2835_alsa_stream { - int running; - int draining; - -+ int channels; -+ int params_rate; -+ int pcm_format_width; -+ - unsigned int pos; - unsigned int buffer_size; - unsigned int period_size; -@@ -138,6 +146,7 @@ typedef struct bcm2835_alsa_stream { - - int snd_bcm2835_new_ctl(bcm2835_chip_t * chip); - int snd_bcm2835_new_pcm(bcm2835_chip_t * chip); -+int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip); - - int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream); - int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream); --- -2.0.3 - - -From 0c6a4e36d07cb9fb43d5d254979de5218b35c24a Mon Sep 17 00:00:00 2001 +From 19efd180a89088d35c6ead0d351c1878996d9c94 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 33/81] dmaengine: Add support for BCM2708 +Subject: [PATCH 30/69] dmaengine: Add support for BCM2708 Add support for DMA controller of BCM2708 as used in the Raspberry Pi. Currently it only supports cyclic DMA. @@ -110112,7 +108418,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 5c58638..63c226e 100644 +index 1eca7b9..720b232 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -312,6 +312,12 @@ config DMA_BCM2835 @@ -110129,7 +108435,7 @@ index 5c58638..63c226e 100644 tristate "AM33xx CPPI41 DMA support" depends on ARCH_OMAP diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile -index 5150c82..b79ee23 100644 +index c779e1e..56b84f2 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o @@ -110738,10 +109044,10 @@ index 0000000..b244293 2.0.3 -From b8478559635687e2511b098b262aa3bf6d42ab6b Mon Sep 17 00:00:00 2001 +From f524482843c30ee526ff78a77bacffb6ebcc67e6 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 34/81] ASoC: Add support for BCM2708 +Subject: [PATCH 31/69] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -111739,10 +110045,10 @@ index 0000000..ebaf3d6 2.0.3 -From ca50f7e68fdf8871d1b8807770a9de9d37469f50 Mon Sep 17 00:00:00 2001 +From 19ec42857fcbc3f67c308de4233e73d89238db05 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:37:51 +0100 -Subject: [PATCH 35/81] BCM2708: Extend mach header +Subject: [PATCH 32/69] BCM2708: Extend mach header Extend the headers of the mach-bcm2708 in order to support I2S and DMA engine. @@ -111787,10 +110093,10 @@ index 992a630..2e7e1bb 100644 2.0.3 -From 32e46d0b5d8db6853a2f29d032bdb950a4a691c3 Mon Sep 17 00:00:00 2001 +From 0d4a090b4d5ee5f36d3c44bad0d9de856e63ae65 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 36/81] ASoC: Add support for PCM5102A codec +Subject: [PATCH 33/69] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -111804,20 +110110,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 f0e8401..269c377 100644 +index 0b9571c..73804ca 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig -@@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS +@@ -74,6 +74,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 -@@ -390,6 +391,9 @@ config SND_SOC_PCM512x_SPI - select SND_SOC_PCM512x - select REGMAP_SPI + select SND_SOC_RT5645 if I2C +@@ -449,6 +450,9 @@ config SND_SOC_RL6231 + default m if SND_SOC_RT5645=m + default m if SND_SOC_RT5651=m +config SND_SOC_PCM5102A + tristate @@ -111826,25 +110132,25 @@ index f0e8401..269c377 100644 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 3c4d275..919b6f6 100644 +index 1bd6e1c..f540cf3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile -@@ -58,6 +58,7 @@ snd-soc-pcm3008-objs := pcm3008.o - snd-soc-pcm512x-objs := pcm512x.o +@@ -68,6 +68,7 @@ snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o + snd-soc-rl6231-objs := rl6231.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 -@@ -209,6 +210,7 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o - obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o + snd-soc-rt5645-objs := rt5645.o +@@ -235,6 +236,7 @@ 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_RL6231) += snd-soc-rl6231.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 - obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o + obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c new file mode 100644 index 0000000..126f1e9 @@ -111918,10 +110224,10 @@ index 0000000..126f1e9 2.0.3 -From 0aba4426d952590c7ee681dc40cd1eaf75111748 Mon Sep 17 00:00:00 2001 +From 9c8424c5317a9398179d788c3fc05a0b55905885 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 37/81] BCM2708: Add I2S support to board file +Subject: [PATCH 34/69] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -111932,7 +110238,7 @@ 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 ef0935f..7cb8a8e 100644 +index a6eb08e..27e47d5 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -615,6 +615,28 @@ static struct platform_device bcm2835_thermal_device = { @@ -111979,10 +110285,10 @@ index ef0935f..7cb8a8e 100644 2.0.3 -From eabb81aacdd552aac86ef6413568e2e24ed16fb2 Mon Sep 17 00:00:00 2001 +From cd2263b1303d573009860feb74caa0faaace47a0 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 38/81] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 35/69] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -112134,10 +110440,10 @@ index 0000000..4b70b45 2.0.3 -From d8973cdaef4eebd635df5f1f4266e2bcb68fca56 Mon Sep 17 00:00:00 2001 +From 54ed9b8bcd8f115b0466bb35fae08f7ad27f4f5c Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 39/81] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 36/69] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -112148,7 +110454,7 @@ 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 7cb8a8e..c4dc10e 100644 +index 27e47d5..fafd8d0 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -637,6 +637,20 @@ static struct platform_device bcm2708_i2s_device = { @@ -112188,10 +110494,10 @@ index 7cb8a8e..c4dc10e 100644 2.0.3 -From 0600c5811c11897ba84efa9ff6e97f9d1f31147b Mon Sep 17 00:00:00 2001 +From 1ce5835d6d9d66f2d42ecb5035abb40fc471d26e Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 18:55:53 +0100 -Subject: [PATCH 40/81] ASoC: BCM2708: Add 24 bit support +Subject: [PATCH 37/69] 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: @@ -112266,10 +110572,10 @@ index ebaf3d6..a179216 100644 2.0.3 -From b203cd6f749cdabddd49fcd7caa6a8eb47b3a84d Mon Sep 17 00:00:00 2001 +From 51ff7226df47992cc46edd4f3ef71cf9c9b374d7 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 2 Dec 2013 20:28:22 +0100 -Subject: [PATCH 41/81] BCM2708: Add I2S and DMA support to default config +Subject: [PATCH 38/69] 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. @@ -112280,10 +110586,10 @@ 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 d70da44..36e7473 100644 +index 0c58172..38ccd22 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -739,6 +739,13 @@ CONFIG_SND_USB_UA101=m +@@ -741,6 +741,13 @@ CONFIG_SND_USB_UA101=m CONFIG_SND_USB_CAIAQ=m CONFIG_SND_USB_CAIAQ_INPUT=y CONFIG_SND_USB_6FIRE=m @@ -112297,7 +110603,7 @@ index d70da44..36e7473 100644 CONFIG_SOUND_PRIME=m CONFIG_HIDRAW=y CONFIG_HID_A4TECH=m -@@ -929,6 +936,10 @@ CONFIG_RTC_DRV_RS5C348=m +@@ -931,6 +938,10 @@ CONFIG_RTC_DRV_RS5C348=m CONFIG_RTC_DRV_DS3234=m CONFIG_RTC_DRV_PCF2123=m CONFIG_RTC_DRV_RX4581=m @@ -112312,10 +110618,10 @@ index d70da44..36e7473 100644 2.0.3 -From fd4a065114c8eaad7536acc3d429556479119b97 Mon Sep 17 00:00:00 2001 +From 7360c30deb09a0c36473fe741f574560e861633f Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 42/81] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 39/69] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -112334,10 +110640,10 @@ 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 36e7473..f877ab2 100644 +index 38ccd22..5e049f9 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -744,8 +744,10 @@ CONFIG_SND_SOC_DMAENGINE_PCM=y +@@ -746,8 +746,10 @@ CONFIG_SND_SOC_DMAENGINE_PCM=y CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y CONFIG_SND_BCM2708_SOC_I2S=m CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m @@ -112349,7 +110655,7 @@ index 36e7473..f877ab2 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 c4dc10e..f2b3990 100644 +index fafd8d0..238f165 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -651,6 +651,20 @@ static struct platform_device snd_pcm5102a_codec_device = { @@ -112516,10 +110822,10 @@ 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 269c377..54dec92 100644 +index 73804ca..0309507 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig -@@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS +@@ -74,6 +74,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 @@ -112527,9 +110833,9 @@ index 269c377..54dec92 100644 select SND_SOC_PCM5102A select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C -@@ -391,6 +392,9 @@ config SND_SOC_PCM512x_SPI - select SND_SOC_PCM512x - select REGMAP_SPI +@@ -450,6 +451,9 @@ config SND_SOC_RL6231 + default m if SND_SOC_RT5645=m + default m if SND_SOC_RT5651=m +config SND_SOC_PCM1794A + tristate @@ -112538,21 +110844,21 @@ index 269c377..54dec92 100644 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 919b6f6..7f0eefa 100644 +index f540cf3..64a04fb 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile -@@ -58,6 +58,7 @@ snd-soc-pcm3008-objs := pcm3008.o - snd-soc-pcm512x-objs := pcm512x.o +@@ -68,6 +68,7 @@ snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o + snd-soc-rl6231-objs := rl6231.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 -@@ -210,6 +211,7 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o - obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o +@@ -236,6 +237,7 @@ 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_RL6231) += snd-soc-rl6231.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 @@ -112629,10 +110935,10 @@ index 0000000..b4eaa44 2.0.3 -From 6dbce2b6f28adfc40b240e9e8f4c820aae638895 Mon Sep 17 00:00:00 2001 +From a36d34e2a8c458ce920925844b3341fcaa53e637 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 43/81] ASoC: wm8804: Implement MCLK configuration options, add +Subject: [PATCH 40/69] 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 @@ -112647,23 +110953,14 @@ This also added support for 32bit data. Signed-off-by: Daniel Matuschek --- - sound/soc/codecs/wm8804.c | 19 +++++++++++++++---- - sound/soc/codecs/wm8804.h | 4 ++++ - 2 files changed, 19 insertions(+), 4 deletions(-) + sound/soc/codecs/wm8804.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c -index ee76f0f..d8923c1 100644 +index d96e5963..9a7a289 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c -@@ -63,6 +63,7 @@ struct wm8804_priv { - struct regmap *regmap; - struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES]; - struct notifier_block disable_nb[WM8804_NUM_SUPPLIES]; -+ int mclk_div; - }; - - static int txsrc_get(struct snd_kcontrol *kcontrol, -@@ -277,6 +278,7 @@ static int wm8804_hw_params(struct snd_pcm_substream *substream, +@@ -278,6 +278,7 @@ static int wm8804_hw_params(struct snd_pcm_substream *substream, blen = 0x1; break; case SNDRV_PCM_FORMAT_S24_LE: @@ -112671,58 +110968,7 @@ index ee76f0f..d8923c1 100644 blen = 0x2; break; default: -@@ -318,7 +320,7 @@ static struct { - - #define FIXED_PLL_SIZE ((1ULL << 22) * 10) - static int pll_factors(struct pll_div *pll_div, unsigned int target, -- unsigned int source) -+ unsigned int source, unsigned int mclk_div) - { - u64 Kpart; - unsigned long int K, Ndiv, Nmod, tmp; -@@ -330,7 +332,8 @@ static int pll_factors(struct pll_div *pll_div, unsigned int target, - */ - for (i = 0; i < ARRAY_SIZE(post_table); i++) { - tmp = target * post_table[i].div; -- if (tmp >= 90000000 && tmp <= 100000000) { -+ if ((tmp >= 90000000 && tmp <= 100000000) && -+ (mclk_div == post_table[i].mclkdiv)) { - pll_div->freqmode = post_table[i].freqmode; - pll_div->mclkdiv = post_table[i].mclkdiv; - target *= post_table[i].div; -@@ -387,8 +390,11 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id, - } else { - int ret; - struct pll_div pll_div; -+ struct wm8804_priv *wm8804; - -- ret = pll_factors(&pll_div, freq_out, freq_in); -+ wm8804 = snd_soc_codec_get_drvdata(codec); -+ -+ ret = pll_factors(&pll_div, freq_out, freq_in, wm8804->mclk_div); - if (ret) - return ret; - -@@ -452,6 +458,7 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai, - int div_id, int div) - { - struct snd_soc_codec *codec; -+ struct wm8804_priv *wm8804; - - codec = dai->codec; - switch (div_id) { -@@ -459,6 +466,10 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai, - snd_soc_update_bits(codec, WM8804_PLL5, 0x30, - (div & 0x3) << 4); - break; -+ case WM8804_MCLK_DIV: -+ wm8804 = snd_soc_codec_get_drvdata(codec); -+ wm8804->mclk_div = div; -+ break; - default: - dev_err(dai->dev, "Unknown clock divider: %d\n", div_id); - return -EINVAL; -@@ -633,7 +644,7 @@ static const struct snd_soc_dai_ops wm8804_dai_ops = { +@@ -641,7 +642,7 @@ static const struct snd_soc_dai_ops wm8804_dai_ops = { }; #define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ @@ -112731,28 +110977,14 @@ index ee76f0f..d8923c1 100644 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ -diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h -index 8ec14f5..e72d4f4 100644 ---- a/sound/soc/codecs/wm8804.h -+++ b/sound/soc/codecs/wm8804.h -@@ -57,5 +57,9 @@ - #define WM8804_CLKOUT_SRC_OSCCLK 4 - - #define WM8804_CLKOUT_DIV 1 -+#define WM8804_MCLK_DIV 2 -+ -+#define WM8804_MCLKDIV_256FS 0 -+#define WM8804_MCLKDIV_128FS 1 - - #endif /* _WM8804_H */ -- 2.0.3 -From b666b1ce160223a3647b4ba8290528de430c2cbc Mon Sep 17 00:00:00 2001 +From 62d7db5f8b54792e1445720cc662cf8aba47b49d Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 44/81] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 41/69] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -112958,10 +111190,10 @@ index 0000000..e4f769d 2.0.3 -From cac75d2346d06b459abd8da150213d726e04d540 Mon Sep 17 00:00:00 2001 +From 18d704577cb6dcf4e86d146753c835f01e5f826a Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 45/81] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 42/69] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -112970,7 +111202,7 @@ 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 f2b3990..f5afd86 100644 +index 238f165..139045b 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -651,6 +651,21 @@ static struct platform_device snd_pcm5102a_codec_device = { @@ -113011,10 +111243,10 @@ index f2b3990..f5afd86 100644 2.0.3 -From 362628023205e4a1a7feac802e11606ac07aa882 Mon Sep 17 00:00:00 2001 +From 9eef4accbfc135975bdc1371284709ca853d2e3d Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:27:28 +0100 -Subject: [PATCH 46/81] BCM2708: Added HiFiBerry Digi configuration option It +Subject: [PATCH 43/69] BCM2708: Added HiFiBerry Digi configuration option It will be compiled as a module by default. This also includes the WM8804 driver. @@ -113024,10 +111256,10 @@ 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 f877ab2..3d3c8ab 100644 +index 5e049f9..4f6bb90 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -742,8 +742,10 @@ CONFIG_SND_USB_6FIRE=m +@@ -744,8 +744,10 @@ CONFIG_SND_USB_6FIRE=m CONFIG_SND_SOC=m CONFIG_SND_SOC_DMAENGINE_PCM=y CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y @@ -113042,10 +111274,10 @@ index f877ab2..3d3c8ab 100644 2.0.3 -From 829e568f8eaeb9c55f524fd4da468fbdf432292e Mon Sep 17 00:00:00 2001 +From d758dd2a339c020ab12e55155025cb9aaac652a0 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 47/81] ASoC: wm8804: Set idle_bias_off to false Idle bias has +Subject: [PATCH 44/69] ASoC: wm8804: Set idle_bias_off to false Idle bias has been change to remove warning on driver startup Signed-off-by: Daniel Matuschek @@ -113054,10 +111286,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 d8923c1..2787042 100644 +index 9a7a289..32e199a 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c -@@ -677,7 +677,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { +@@ -675,7 +675,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .suspend = wm8804_suspend, .resume = wm8804_resume, .set_bias_level = wm8804_set_bias_level, @@ -113070,10 +111302,10 @@ index d8923c1..2787042 100644 2.0.3 -From 6e42995fc84a6229fb548777b73d75f74256543f Mon Sep 17 00:00:00 2001 +From 595a565de57c50b73832c62d0fe862ad1f8489d2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 12 Mar 2014 11:46:34 +0000 -Subject: [PATCH 48/81] ASoc: Don't report S24_LE support, it produces white +Subject: [PATCH 45/69] ASoc: Don't report S24_LE support, it produces white noise with xbmc --- @@ -113111,29 +111343,25 @@ index 126f1e9..7812d34 100644 2.0.3 -From 53992323fb8a9c6e234acbf216506bc84663100b Mon Sep 17 00:00:00 2001 +From 4a6f55a4abbf3506ca7919d1c95a2be3b952277d Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 49/81] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 46/69] 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/codecs/Kconfig | 4 + - sound/soc/codecs/Makefile | 2 + - sound/soc/codecs/pcm512x.c | 243 ++++++++++++++++++++++++++------------ - sound/soc/codecs/pcm512x.h | 143 +++++++++------------- - 9 files changed, 372 insertions(+), 163 deletions(-) + sound/soc/bcm/iqaudio-dac.c | 111 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 143 insertions(+) create mode 100644 sound/soc/bcm/iqaudio-dac.c diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 3d3c8ab..a024670 100644 +index 4f6bb90..105bcbe 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -750,6 +750,7 @@ CONFIG_SND_BCM2708_SOC_RPI_DAC=m +@@ -752,6 +752,7 @@ CONFIG_SND_BCM2708_SOC_RPI_DAC=m CONFIG_SND_SOC_I2C_AND_SPI=m CONFIG_SND_SOC_PCM5102A=m CONFIG_SND_SOC_PCM1794A=m @@ -113142,7 +111370,7 @@ index 3d3c8ab..a024670 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 f5afd86..b0aec82 100644 +index 139045b..f717a59 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -680,6 +680,22 @@ static struct platform_device snd_pcm1794a_codec_device = { @@ -113182,7 +111410,7 @@ index f5afd86..b0aec82 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index e563dbc..84e4f27 100644 +index e563dbc..c621a5e 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig @@ -39,3 +39,10 @@ config SND_BCM2708_SOC_RPI_DAC @@ -113193,7 +111421,7 @@ index e563dbc..84e4f27 100644 +config SND_BCM2708_SOC_IQAUDIO_DAC + tristate "Support for IQaudIO-DAC" + depends on SND_BCM2708_SOC_I2S -+ select SND_SOC_PCM512x ++ select SND_SOC_PCM512x_I2C + help + Say Y or M if you want to add support for IQaudIO-DAC. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile @@ -113212,7 +111440,7 @@ index 826df7d..d597fb0 100644 +obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c new file mode 100644 -index 0000000..515f044 +index 0000000..8d0e2ae --- /dev/null +++ b/sound/soc/bcm/iqaudio-dac.c @@ -0,0 +1,111 @@ @@ -113284,7 +111512,7 @@ index 0000000..515f044 + +/* audio machine driver */ +static struct snd_soc_card snd_rpi_iqaudio_dac = { -+ .name = "snd_rpi_iqaudio_dac", ++ .name = "IQaudIODAC", + .dai_link = snd_rpi_iqaudio_dac_dai, + .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai), +}; @@ -113327,605 +111555,17 @@ index 0000000..515f044 +MODULE_AUTHOR("Florian Meier "); +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 54dec92..b3a0488 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -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 -@@ -398,6 +399,9 @@ config SND_SOC_PCM1794A - config SND_SOC_PCM5102A - tristate - -+config SND_SOC_PCM512x -+ tristate -+ - config SND_SOC_RT5631 - tristate - -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 7f0eefa..95600ec 100644 ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -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 -@@ -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 - obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o - 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 -index 4b4c0c7..b669e15 100644 ---- a/sound/soc/codecs/pcm512x.c -+++ b/sound/soc/codecs/pcm512x.c -@@ -18,9 +18,11 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include - #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", -@@ -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 }, -+ { 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 }, - }; - - 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; - } - } - -@@ -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(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", -- "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 = -- 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 = -- 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 = -- SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, -+ SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 7, - 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" - }; -@@ -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" - }; - -@@ -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, - -- .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", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, pcm512x_of_match); -+ -+static int pcm512x_probe(struct device *dev, struct regmap *regmap) - { - 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: -@@ -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); - -@@ -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); -@@ -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) - }; --EXPORT_SYMBOL_GPL(pcm512x_pm_ops); -+ -+#if IS_ENABLED(CONFIG_I2C) -+static int pcm512x_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) -+{ -+ struct regmap *regmap; -+ -+ regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); -+ -+ return pcm512x_probe(&i2c->dev, regmap); -+} -+ -+static int pcm512x_i2c_remove(struct i2c_client *i2c) -+{ -+ pcm512x_remove(&i2c->dev); -+ return 0; -+} -+ -+static const struct i2c_device_id pcm512x_i2c_id[] = { -+ { "pcm5121", }, -+ { "pcm5122", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); -+ -+static struct i2c_driver pcm512x_i2c_driver = { -+ .probe = pcm512x_i2c_probe, -+ .remove = pcm512x_i2c_remove, -+ .id_table = pcm512x_i2c_id, -+ .driver = { -+ .name = "pcm512x", -+ .owner = THIS_MODULE, -+ .of_match_table = pcm512x_of_match, -+ .pm = &pcm512x_pm_ops, -+ }, -+}; -+#endif -+ -+#if defined(CONFIG_SPI_MASTER) -+static int pcm512x_spi_probe(struct spi_device *spi) -+{ -+ struct regmap *regmap; -+ int ret; -+ -+ regmap = devm_regmap_init_spi(spi, &pcm512x_regmap); -+ if (IS_ERR(regmap)) { -+ ret = PTR_ERR(regmap); -+ return ret; -+ } -+ -+ return pcm512x_probe(&spi->dev, regmap); -+} -+ -+static int pcm512x_spi_remove(struct spi_device *spi) -+{ -+ pcm512x_remove(&spi->dev); -+ return 0; -+} -+ -+static const struct spi_device_id pcm512x_spi_id[] = { -+ { "pcm5121", }, -+ { "pcm5122", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); -+ -+static struct spi_driver pcm512x_spi_driver = { -+ .probe = pcm512x_spi_probe, -+ .remove = pcm512x_spi_remove, -+ .id_table = pcm512x_spi_id, -+ .driver = { -+ .name = "pcm512x", -+ .owner = THIS_MODULE, -+ .of_match_table = pcm512x_of_match, -+ .pm = &pcm512x_pm_ops, -+ }, -+}; -+#endif -+ -+static int __init pcm512x_modinit(void) -+{ -+ int ret = 0; -+ -+#if IS_ENABLED(CONFIG_I2C) -+ ret = i2c_add_driver(&pcm512x_i2c_driver); -+ if (ret) { -+ printk(KERN_ERR "Failed to register pcm512x I2C driver: %d\n", -+ ret); -+ } -+#endif -+#if defined(CONFIG_SPI_MASTER) -+ ret = spi_register_driver(&pcm512x_spi_driver); -+ if (ret != 0) { -+ printk(KERN_ERR "Failed to register pcm512x SPI driver: %d\n", -+ ret); -+ } -+#endif -+ return ret; -+} -+module_init(pcm512x_modinit); -+ -+static void __exit pcm512x_exit(void) -+{ -+#if IS_ENABLED(CONFIG_I2C) -+ i2c_del_driver(&pcm512x_i2c_driver); -+#endif -+#if defined(CONFIG_SPI_MASTER) -+ spi_unregister_driver(&pcm512x_spi_driver); -+#endif -+} -+module_exit(pcm512x_exit); - - MODULE_DESCRIPTION("ASoC PCM512x codec driver"); - MODULE_AUTHOR("Mark Brown "); -diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h -index 6ee76aa..b2f518e 100644 ---- a/sound/soc/codecs/pcm512x.h -+++ b/sound/soc/codecs/pcm512x.h -@@ -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_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) -+#define PCM512x_PLL_EN (PCM512x_PAGE_0_BASE + 4) -+#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_0_BASE + 6) -+#define PCM512x_DSP (PCM512x_PAGE_0_BASE + 7) -+#define PCM512x_GPIO_EN (PCM512x_PAGE_0_BASE + 8) -+#define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_0_BASE + 9) -+#define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_0_BASE + 10) -+#define PCM512x_MASTER_MODE (PCM512x_PAGE_0_BASE + 12) -+#define PCM512x_PLL_REF (PCM512x_PAGE_0_BASE + 13) -+#define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_0_BASE + 20) -+#define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_0_BASE + 21) -+#define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_0_BASE + 22) -+#define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_0_BASE + 23) -+#define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_0_BASE + 24) -+#define PCM512x_DSP_CLKDIV (PCM512x_PAGE_0_BASE + 27) -+#define PCM512x_DAC_CLKDIV (PCM512x_PAGE_0_BASE + 28) -+#define PCM512x_NCP_CLKDIV (PCM512x_PAGE_0_BASE + 29) -+#define PCM512x_OSR_CLKDIV (PCM512x_PAGE_0_BASE + 30) -+#define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_0_BASE + 32) -+#define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_0_BASE + 33) -+#define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_0_BASE + 34) -+#define PCM512x_IDAC_1 (PCM512x_PAGE_0_BASE + 35) -+#define PCM512x_IDAC_2 (PCM512x_PAGE_0_BASE + 36) -+#define PCM512x_ERROR_DETECT (PCM512x_PAGE_0_BASE + 37) -+#define PCM512x_I2S_1 (PCM512x_PAGE_0_BASE + 40) -+#define PCM512x_I2S_2 (PCM512x_PAGE_0_BASE + 41) -+#define PCM512x_DAC_ROUTING (PCM512x_PAGE_0_BASE + 42) -+#define PCM512x_DSP_PROGRAM (PCM512x_PAGE_0_BASE + 43) -+#define PCM512x_CLKDET (PCM512x_PAGE_0_BASE + 44) -+#define PCM512x_AUTO_MUTE (PCM512x_PAGE_0_BASE + 59) -+#define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_0_BASE + 60) -+#define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_0_BASE + 61) -+#define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_0_BASE + 62) -+#define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_0_BASE + 63) -+#define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_0_BASE + 64) -+#define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_0_BASE + 65) -+#define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_0_BASE + 80) -+#define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_0_BASE + 81) -+#define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_0_BASE + 82) -+#define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_0_BASE + 83) -+#define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_0_BASE + 84) -+#define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_0_BASE + 85) -+#define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_0_BASE + 86) -+#define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_0_BASE + 87) -+#define PCM512x_OVERFLOW (PCM512x_PAGE_0_BASE + 90) -+#define PCM512x_RATE_DET_1 (PCM512x_PAGE_0_BASE + 91) -+#define PCM512x_RATE_DET_2 (PCM512x_PAGE_0_BASE + 92) -+#define PCM512x_RATE_DET_3 (PCM512x_PAGE_0_BASE + 93) -+#define PCM512x_RATE_DET_4 (PCM512x_PAGE_0_BASE + 94) -+#define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_0_BASE + 108) -+#define PCM512x_GPIN (PCM512x_PAGE_0_BASE + 119) -+#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) -@@ -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 -- 2.0.3 -From 1ecb76a87dffdb1b19210c4fcb8354815d39eec7 Mon Sep 17 00:00:00 2001 +From f0483731ee783f911bd4976eb8b186e0494538ea Mon Sep 17 00:00:00 2001 From: Howard Mitchell -Date: Fri, 28 Mar 2014 16:27:57 +0000 -Subject: [PATCH 50/81] Fix volsw_range functions so SOC_DOUBLE_R_RANGE_TLV - works. +Date: Wed, 30 Jul 2014 21:43:37 +0100 +Subject: [PATCH 47/69] soc-core: Fix volsw_range funcs so + SOC_DOUBLE_R_RANGE_TLV works. -This is so that the correct rabge of values as specified +This is so that the correct range of values as specified with the SOC_DOUBLE_R_RANGE_TLV macro are sent to the hardware for both the normal and invert cases. --- @@ -113933,10 +111573,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 051c006..bf39f16 100644 +index b87d7d8..1f3d03e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c -@@ -3024,8 +3024,8 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, +@@ -2973,8 +2973,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; @@ -113947,7 +111587,7 @@ index 051c006..bf39f16 100644 return 0; } -@@ -3056,9 +3056,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, +@@ -3005,9 +3005,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, unsigned int val, val_mask; int ret; @@ -113955,12 +111595,12 @@ index 051c006..bf39f16 100644 if (invert) - val = max - val; + val = ((max - ucontrol->value.integer.value[0] + min) & mask); -+ else -+ val = (ucontrol->value.integer.value[0] & mask); ++ else ++ val = (ucontrol->value.integer.value[0] & mask); val_mask = mask << shift; val = val << shift; -@@ -3067,9 +3068,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, +@@ -3016,9 +3017,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, return ret; if (snd_soc_volsw_is_stereo(mc)) { @@ -113968,13 +111608,13 @@ index 051c006..bf39f16 100644 if (invert) - val = max - val; + val = ((max - ucontrol->value.integer.value[1] + min) & mask); -+ else -+ val = (ucontrol->value.integer.value[1] & mask); ++ else ++ val = (ucontrol->value.integer.value[1] & mask); val_mask = mask << shift; val = val << shift; -@@ -3107,18 +3109,14 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, - (snd_soc_read(codec, reg) >> shift) & mask; +@@ -3062,9 +3064,7 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, + ucontrol->value.integer.value[0] = (val >> shift) & mask; if (invert) ucontrol->value.integer.value[0] = - max - ucontrol->value.integer.value[0]; @@ -113983,8 +111623,9 @@ index 051c006..bf39f16 100644 + max - ucontrol->value.integer.value[0] + min; if (snd_soc_volsw_is_stereo(mc)) { - ucontrol->value.integer.value[1] = - (snd_soc_read(codec, rreg) >> shift) & mask; + ret = snd_soc_component_read(component, rreg, &val); +@@ -3074,9 +3074,7 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, + ucontrol->value.integer.value[1] = (val >> shift) & mask; if (invert) ucontrol->value.integer.value[1] = - max - ucontrol->value.integer.value[1]; @@ -113998,50 +111639,41 @@ index 051c006..bf39f16 100644 2.0.3 -From d1888d1dc197d62733b3e27b33ac869d5b7d2598 Mon Sep 17 00:00:00 2001 -From: Gordon Garrity -Date: Sun, 30 Mar 2014 13:52:33 +0100 -Subject: [PATCH 51/81] fix soc-core's inverse range and let IQaudIO DAC use - this fixed SOC_DOUBLE_R_RANGE_TLV support +From e242ee32e3c4a87c70242c472fd534b30d096dbb Mon Sep 17 00:00:00 2001 +From: Howard Mitchell +Date: Fri, 28 Mar 2014 16:40:31 +0000 +Subject: [PATCH 48/69] pcm512x: Use a range macro for Volume and rename to + PCM. +This allows limiting the output gain to avoid clipping in the +DAC ouput stages. --- - sound/soc/soc-core.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) + sound/soc/codecs/pcm512x.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) -diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index bf39f16..4d8917b 100644 ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -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); -- else -- val = (ucontrol->value.integer.value[0] & mask); -+ else -+ val = (ucontrol->value.integer.value[0] & mask); - val_mask = mask << shift; - val = val << shift; - -@@ -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); -- else -- val = (ucontrol->value.integer.value[1] & mask); -+ else -+ val = (ucontrol->value.integer.value[1] & mask); - val_mask = mask << shift; - val = val << shift; +diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c +index 163ec38..1466955 100644 +--- a/sound/soc/codecs/pcm512x.c ++++ b/sound/soc/codecs/pcm512x.c +@@ -259,8 +259,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("PCM", PCM512x_DIGITAL_VOLUME_2, ++ PCM512x_DIGITAL_VOLUME_3, 0, 40, 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, -- 2.0.3 -From 07807526329cc3fd714388368b40970785909957 Mon Sep 17 00:00:00 2001 +From b24c3177b927a6c9fdec4bbd6dad6e13deb72bb9 Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Fri, 2 May 2014 16:13:59 +0100 -Subject: [PATCH 52/81] Move GPIO setup to hw_params. +Subject: [PATCH 49/69] 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 @@ -114140,88 +111772,10 @@ index b25e158..9976571 100644 2.0.3 -From d9d0787e5e29f0f4ced9d956ca825a238f690abb Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 9 May 2014 15:45:13 +0100 -Subject: [PATCH 53/81] fb: distinguish physical and bus addresses - ---- - drivers/video/fbdev/bcm2708_fb.c | 15 +++++++++------ - 1 file changed, 9 insertions(+), 6 deletions(-) - -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; - }; - - #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 - fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; - -+ 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) - } - 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, --- -2.0.3 - - -From aae0497628858b47a9e39ecdf9cc45dda3b20597 Mon Sep 17 00:00:00 2001 +From 643b0d8e1ca78ed65aaba5cbebd56aa4a3cc9d5d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Jun 2014 13:42:01 +0100 -Subject: [PATCH 54/81] vmstat: Workaround for issue where dirty page count +Subject: [PATCH 50/69] vmstat: Workaround for issue where dirty page count goes negative See: @@ -114232,10 +111786,10 @@ http://www.spinics.net/lists/linux-mm/msg72236.html 1 file changed, 4 insertions(+) diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h -index 45c9cd1..07dad05 100644 +index 82e7db7..f87d16d 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h -@@ -235,7 +235,11 @@ static inline void __inc_zone_state(struct zone *zone, enum zone_stat_item item) +@@ -241,7 +241,11 @@ static inline void __inc_zone_state(struct zone *zone, enum zone_stat_item item) static inline void __dec_zone_state(struct zone *zone, enum zone_stat_item item) { atomic_long_dec(&zone->vm_stat[item]); @@ -114251,10 +111805,10 @@ index 45c9cd1..07dad05 100644 2.0.3 -From 7c120aa95793cd46f9119514347014d280ae927e Mon Sep 17 00:00:00 2001 +From ca66969e4920c7e099d31327339f5e6a5a51d459 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Jun 2014 16:03:12 +0100 -Subject: [PATCH 55/81] dwc_otg: Fix various issues with root port and +Subject: [PATCH 51/69] dwc_otg: Fix various issues with root port and transaction errors Process the host port interrupts correctly (and don't trample them). @@ -114327,10 +111881,10 @@ index d3e2035..6182d3e 100644 2.0.3 -From 01edef697dfd9bd286805a6cce572b75450cd72e Mon Sep 17 00:00:00 2001 +From aa85957ab787ff35e792631430c4ac2438803901 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Jun 2014 17:23:20 +0100 -Subject: [PATCH 56/81] fiq_fsm: Implement hack for Split Interrupt +Subject: [PATCH 52/69] fiq_fsm: Implement hack for Split Interrupt transactions Hubs aren't too picky about which endpoint we send Control type split @@ -114419,10 +111973,10 @@ index daea770..35721e5 100644 2.0.3 -From 187d9505cbfa744025a023fdcd8f552d681f802f Mon Sep 17 00:00:00 2001 +From b0db7da4db5e72e4b971ef4fa41122d547ad629c Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:07:25 +0200 -Subject: [PATCH 57/81] spi-bcm2708: Prepare for Common Clock Framework +Subject: [PATCH 53/69] spi-bcm2708: Prepare for Common Clock Framework migration As part of migrating to use the Common Clock Framework, replace clk_enable() @@ -114437,7 +111991,7 @@ Signed-off-by: Noralf Tronnes 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-bcm2708.c b/drivers/spi/spi-bcm2708.c -index 06dd02f..0952f40 100644 +index b04a57d..349d21f 100644 --- a/drivers/spi/spi-bcm2708.c +++ b/drivers/spi/spi-bcm2708.c @@ -545,7 +545,7 @@ static int bcm2708_spi_probe(struct platform_device *pdev) @@ -114459,7 +112013,7 @@ index 06dd02f..0952f40 100644 out_iounmap: @@ -585,7 +586,7 @@ static int bcm2708_spi_remove(struct platform_device *pdev) - flush_work_sync(&bs->work); + flush_work(&bs->work); - clk_disable(bs->clk); + clk_disable_unprepare(bs->clk); @@ -114470,10 +112024,10 @@ index 06dd02f..0952f40 100644 2.0.3 -From b5be9cb4072736e3fe0420ab02d38cc306b070b3 Mon Sep 17 00:00:00 2001 +From 110dc4edc8772481c62f1837cf5a7b9d1d5ffcd1 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:09:30 +0200 -Subject: [PATCH 58/81] BCM2708: Migrate to the Common Clock Framework +Subject: [PATCH 54/69] BCM2708: Migrate to the Common Clock Framework As part of moving towards using Device Tree, the Common Clock Framework has to be used instead of the BCM2708 clock implementation. @@ -114486,18 +112040,18 @@ Signed-off-by: Noralf Tronnes --- arch/arm/Kconfig | 3 +- arch/arm/mach-bcm2708/Makefile | 2 +- - arch/arm/mach-bcm2708/bcm2708.c | 84 ++++++++++++++++++----------------------- - arch/arm/mach-bcm2708/clock.c | 61 ------------------------------ - arch/arm/mach-bcm2708/clock.h | 24 ------------ - 5 files changed, 39 insertions(+), 135 deletions(-) + arch/arm/mach-bcm2708/bcm2708.c | 79 +++++++++++++++++------------------------ + arch/arm/mach-bcm2708/clock.c | 61 ------------------------------- + arch/arm/mach-bcm2708/clock.h | 24 ------------- + 5 files changed, 34 insertions(+), 135 deletions(-) delete mode 100644 arch/arm/mach-bcm2708/clock.c delete mode 100644 arch/arm/mach-bcm2708/clock.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index ac5410d..d780a9f 100644 +index d0c3229..9ff6999 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -389,11 +389,10 @@ config ARCH_BCM2708 +@@ -378,11 +378,10 @@ config ARCH_BCM2708 bool "Broadcom BCM2708 family" select CPU_V6 select ARM_AMBA @@ -114523,7 +112077,7 @@ index a722f3f..21e3521 100644 obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index b0aec82..26fe14e 100644 +index f717a59..674e5aa 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -27,6 +27,8 @@ @@ -114552,7 +112106,7 @@ index b0aec82..26fe14e 100644 static unsigned disk_led_gpio = 16; static unsigned disk_led_active_low = 1; static unsigned reboot_part = 0; -@@ -196,51 +197,44 @@ static void __init bcm2708_clocksource_init(void) +@@ -196,51 +197,39 @@ static void __init bcm2708_clocksource_init(void) } } @@ -114624,11 +112178,6 @@ index b0aec82..26fe14e 100644 + clk = bcm2708_clk_register("uart0_clk", uart_clock); + bcm2708_register_clkdev(clk, "dev:f1"); + -+ /* ARM clock is set from the VideoCore booter */ -+ /* warning - the USB needs a clock > 34MHz */ -+ clk = bcm2708_clk_register("osc_clk", 500000000); -+ bcm2708_register_clkdev(clk, "bcm2708_usb"); -+ + clk = bcm2708_clk_register("sdhost_clk", 250000000); + bcm2708_register_clkdev(clk, "bcm2708_spi.0"); + bcm2708_register_clkdev(clk, "bcm2708_i2c.0"); @@ -114637,7 +112186,7 @@ index b0aec82..26fe14e 100644 #define UART0_IRQ { IRQ_UART, 0 /*NO_IRQ*/ } #define UART0_DMA { 15, 14 } -@@ -783,11 +777,7 @@ void __init bcm2708_init(void) +@@ -783,11 +772,7 @@ void __init bcm2708_init(void) printk("bcm2708.uart_clock = %d\n", uart_clock); pm_power_off = bcm2708_power_off; @@ -114751,122 +112300,10 @@ index 5f9d725..0000000 2.0.3 -From 26e1575fcc4b567aba504609c16ac5015d758f85 Mon Sep 17 00:00:00 2001 -From: notro -Date: Sun, 6 Jul 2014 16:31:31 +0200 -Subject: [PATCH 59/81] BCM2708: remove 'bcm2708_usb' clkdev - -'bcm2708_usb' is currently not in use by the USB OTG driver. - -Signed-off-by: Noralf Tronnes ---- - arch/arm/mach-bcm2708/bcm2708.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 26fe14e..ef5a55dc 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -225,11 +225,6 @@ void __init bcm2708_init_clocks(void) - clk = bcm2708_clk_register("uart0_clk", uart_clock); - bcm2708_register_clkdev(clk, "dev:f1"); - -- /* ARM clock is set from the VideoCore booter */ -- /* warning - the USB needs a clock > 34MHz */ -- clk = bcm2708_clk_register("osc_clk", 500000000); -- bcm2708_register_clkdev(clk, "bcm2708_usb"); -- - clk = bcm2708_clk_register("sdhost_clk", 250000000); - bcm2708_register_clkdev(clk, "bcm2708_spi.0"); - bcm2708_register_clkdev(clk, "bcm2708_i2c.0"); --- -2.0.3 - - -From 045f79a82dc551affa47060c73487b63aec7ce08 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 4 Jul 2014 22:54:16 +0100 -Subject: [PATCH 60/81] config: Add CONFIG_DEVPTS_MULTIPLE_INSTANCES - ---- - 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 a024670..29fe486 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -528,6 +528,7 @@ CONFIG_SERIO_RAW=m - CONFIG_GAMEPORT=m - CONFIG_GAMEPORT_NS558=m - CONFIG_GAMEPORT_L4=m -+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y - # CONFIG_LEGACY_PTYS is not set - # CONFIG_DEVKMEM is not set - CONFIG_SERIAL_AMBA_PL011=y --- -2.0.3 - - -From 0a1408c4901dc73575a1db8208ebd3cc41a1cdeb Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 26 Jun 2014 19:03:47 +0100 -Subject: [PATCH 61/81] bcm2708: Avoid hang when timer_set_next_event is called - with MAX_INT - -See: https://github.com/raspberrypi/linux/issues/616 ---- - arch/arm/mach-bcm2708/bcm2708.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index ef5a55dc..9bf2508 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -870,7 +870,8 @@ static int timer_set_next_event(unsigned long cycles, - 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) -+ } while ((signed long) cycles >= 0 && -+ (signed long) (readl(__io_address(ST_BASE + 0x04)) - stc) - >= (signed long) cycles); - return 0; - } --- -2.0.3 - - -From 853943bf0d83b8136f2bc610e39645caf88f1a50 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 26 Jun 2014 19:00:28 +0100 -Subject: [PATCH 62/81] armctrl: Don't mask interrupts from ack - ---- - arch/arm/mach-bcm2708/armctrl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm/mach-bcm2708/armctrl.c b/arch/arm/mach-bcm2708/armctrl.c -index 274aa30..d4c5333 100644 ---- a/arch/arm/mach-bcm2708/armctrl.c -+++ b/arch/arm/mach-bcm2708/armctrl.c -@@ -184,7 +184,7 @@ late_initcall(armctrl_syscore_init); - - static struct irq_chip armctrl_chip = { - .name = "ARMCTRL", -- .irq_ack = armctrl_mask_irq, -+ .irq_ack = NULL, - .irq_mask = armctrl_mask_irq, - .irq_unmask = armctrl_unmask_irq, - .irq_set_wake = armctrl_set_wake, --- -2.0.3 - - -From d3963b77dd15a714e6ee7aa0a33ca16b1b8465f9 Mon Sep 17 00:00:00 2001 +From bb8acd988f2d8152964e340ff69df2286360764f Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 63/81] BCM2708: Add core Device Tree support +Subject: [PATCH 55/69] BCM2708: Add core Device Tree support Add the bare minimum needed to boot BCM2708 from a Device Tree. @@ -114882,13 +112319,13 @@ Signed-off-by: Noralf Tronnes create mode 100644 arch/arm/boot/dts/bcm2708.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index 377b7c3..c118dc8 100644 +index adb5ed9..942249e 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -50,6 +50,7 @@ dtb-$(CONFIG_ARCH_AT91) += sama5d35ek.dtb - dtb-$(CONFIG_ARCH_AT91) += sama5d36ek.dtb +@@ -51,6 +51,7 @@ dtb-$(CONFIG_ARCH_AT91) += sama5d36ek.dtb dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb + dtb-$(CONFIG_ARCH_AXXIA) += axm5516-amarillo.dtb +dtb-$(CONFIG_BCM2708_DT) += bcm2708-rpi-b.dtb dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb @@ -114960,7 +112397,7 @@ index e151ed4..182e7ba 100644 bool "BCM2708 gpio support" depends on MACH_BCM2708 diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 9bf2508..6929e2e 100644 +index 674e5aa..83277d1f 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -33,6 +33,7 @@ @@ -115026,10 +112463,10 @@ index 9bf2508..6929e2e 100644 2.0.3 -From 2fc5486e1cd396c0185d71da74e8d99b01638a94 Mon Sep 17 00:00:00 2001 +From 8312254c3a0888c0a85cb5dbf414d458fee5e74a Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:47:48 +0200 -Subject: [PATCH 64/81] BCM2708: armctrl: Add IRQ Device Tree support +Subject: [PATCH 56/69] BCM2708: armctrl: Add IRQ Device Tree support Add Device Tree IRQ support for BCM2708. Usage is the same as for irq-bcm2835. @@ -115196,10 +112633,10 @@ index d4c5333..42f5e1c 100644 2.0.3 -From 58c36be1efe648bf73f27c37ea50ea88619e7515 Mon Sep 17 00:00:00 2001 +From bd0a5027902f169c9dd9b007ebf5ded0ff126d71 Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 65/81] pinctrl: add bcm2708 driver +Subject: [PATCH 57/69] pinctrl: add bcm2708 driver This driver is a verbatim copy of the pinctrl-bcm2835 driver, except for: * changed 2835 to 2708 @@ -115255,10 +112692,10 @@ index 182e7ba..05945d6 100644 Enable Device Tree support for BCM2708 diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig -index e00c02d..1279285 100644 +index 0042ccb..6b55773 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig -@@ -99,6 +99,11 @@ config PINCTRL_BAYTRAIL +@@ -102,6 +102,11 @@ config PINCTRL_BAYTRAIL Requires ACPI device enumeration code to set up a platform device. @@ -115271,7 +112708,7 @@ index e00c02d..1279285 100644 bool select PINMUX diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile -index 6d3fd62..eecc87d 100644 +index c4b5d40..916fc61 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o @@ -116065,487 +113502,18 @@ index 0000000..40d9c86 2.0.3 -From 671c433f3e138539ecaa6d7368c1184442992e7a Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 6 Jul 2014 14:58:44 +0100 -Subject: [PATCH 66/81] snd-bcm2708: Add mutex, improve logging - ---- - sound/arm/bcm2835-pcm.c | 35 +++++++++++++++-- - sound/arm/bcm2835-vchiq.c | 95 +++++++++++++++++++++++++++++------------------ - sound/arm/bcm2835.h | 1 + - 3 files changed, 92 insertions(+), 39 deletions(-) - -diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c -index ebd3f62..0929e00 100755 ---- a/sound/arm/bcm2835-pcm.c -+++ b/sound/arm/bcm2835-pcm.c -@@ -119,6 +119,11 @@ static int snd_bcm2835_playback_open_generic( - - audio_info(" .. IN (%d)\n", substream->number); - -+ if(mutex_lock_interruptible(&chip->audio_mutex)) -+ { -+ audio_error("Interrupted whilst waiting for lock\n"); -+ return -EINTR; -+ } - audio_info("Alsa open (%d)\n", substream->number); - idx = substream->number; - -@@ -145,7 +150,8 @@ static int snd_bcm2835_playback_open_generic( - - alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL); - if (alsa_stream == NULL) { -- return -ENOMEM; -+ err = -ENOMEM; -+ goto out; - } - - /* Initialise alsa_stream */ -@@ -186,6 +192,8 @@ static int snd_bcm2835_playback_open_generic( - alsa_stream->draining = 1; - - out: -+ mutex_unlock(&chip->audio_mutex); -+ - audio_info(" .. OUT =%d\n", err); - - return err; -@@ -206,11 +214,16 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) - { - /* the hardware-specific codes will be here */ - -+ audio_info(" .. IN\n"); -+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); -+ if(mutex_lock_interruptible(&chip->audio_mutex)) -+ { -+ audio_error("Interrupted whilst waiting for lock\n"); -+ return -EINTR; -+ } - struct snd_pcm_runtime *runtime = substream->runtime; - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; -- bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); - -- audio_info(" .. IN\n"); - audio_info("Alsa close\n"); - - /* -@@ -241,6 +254,7 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) - - chip->opened &= ~(1 << substream->number); - -+ mutex_unlock(&chip->audio_mutex); - audio_info(" .. OUT\n"); - - return 0; -@@ -469,6 +483,12 @@ int snd_bcm2835_new_pcm(bcm2835_chip_t * chip) - int err; - - audio_info(" .. IN\n"); -+ mutex_init(&chip->audio_mutex); -+ if(mutex_lock_interruptible(&chip->audio_mutex)) -+ { -+ audio_error("Interrupted whilst waiting for lock\n"); -+ return -EINTR; -+ } - err = - snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm); - if (err < 0) -@@ -490,6 +510,7 @@ int snd_bcm2835_new_pcm(bcm2835_chip_t * chip) - (GFP_KERNEL), 64 * 1024, - 64 * 1024); - -+ mutex_unlock(&chip->audio_mutex); - audio_info(" .. OUT\n"); - - return 0; -@@ -500,6 +521,12 @@ int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip) - struct snd_pcm *pcm; - int err; - -+ audio_info(" .. IN\n"); -+ if(mutex_lock_interruptible(&chip->audio_mutex)) -+ { -+ audio_error("Interrupted whilst waiting for lock\n"); -+ return -EINTR; -+ } - err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm); - if (err < 0) - return err; -@@ -513,6 +540,8 @@ int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip) - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data (GFP_KERNEL), - 64 * 1024, 64 * 1024); -+ mutex_unlock(&chip->audio_mutex); -+ audio_info(" .. OUT\n"); - - return 0; - } -diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c -index ee09b13..70f37a5 100755 ---- a/sound/arm/bcm2835-vchiq.c -+++ b/sound/arm/bcm2835-vchiq.c -@@ -200,14 +200,22 @@ static void audio_vchi_callback(void *param, - int32_t status; - int32_t msg_len; - VC_AUDIO_MSG_T m; -- bcm2835_alsa_stream_t *alsa_stream = 0; -- LOG_DBG(" .. IN instance=%p, param=%p, reason=%d, handle=%p\n", -- instance, param, reason, msg_handle); -+ LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n", -+ instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle); - -- if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) { -+ if (reason != VCHI_CALLBACK_MSG_AVAILABLE) { - return; - } -- alsa_stream = instance->alsa_stream; -+ if (!instance) { -+ LOG_ERR(" .. instance is null\n"); -+ BUG(); -+ return; -+ } -+ if (!instance->vchi_handle[0]) { -+ LOG_ERR(" .. instance->vchi_handle[0] is null\n"); -+ BUG(); -+ return; -+ } - status = vchi_msg_dequeue(instance->vchi_handle[0], - &m, sizeof m, &msg_len, VCHI_FLAGS_NONE); - if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { -@@ -217,6 +225,7 @@ static void audio_vchi_callback(void *param, - instance->result = m.u.result.success; - complete(&instance->msg_avail_comp); - } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { -+ bcm2835_alsa_stream_t *alsa_stream = instance->alsa_stream; - irq_handler_t callback = (irq_handler_t) m.u.complete.callback; - LOG_DBG - (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n", -@@ -225,11 +234,11 @@ static void audio_vchi_callback(void *param, - atomic_add(m.u.complete.count, &alsa_stream->retrieved); - callback(0, alsa_stream); - } else { -- LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n", -+ LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n", - alsa_stream, callback); - } - } else { -- LOG_DBG(" .. unexpected m.type=%d\n", m.type); -+ LOG_ERR(" .. unexpected m.type=%d\n", m.type); - } - LOG_DBG(" .. OUT\n"); - } -@@ -253,6 +262,8 @@ static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance, - } - /* Allocate memory for this instance */ - instance = kmalloc(sizeof(*instance), GFP_KERNEL); -+ if (!instance) -+ return NULL; - - memset(instance, 0, sizeof(*instance)); - instance->num_connections = num_connections; -@@ -274,8 +285,10 @@ static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance, - 0 // want crc check on bulk transfers - }; - -+ LOG_DBG("%s: about to open %i\n", __func__, i); - status = vchi_service_open(vchi_instance, ¶ms, - &instance->vchi_handle[i]); -+ LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status); - if (status) { - LOG_ERR - ("%s: failed to open VCHI service connection (status=%d)\n", -@@ -287,14 +300,18 @@ static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance, - vchi_service_release(instance->vchi_handle[i]); - } - -+ LOG_DBG("%s: okay\n", __func__); - return instance; - - err_close_services: - for (i = 0; i < instance->num_connections; i++) { -- vchi_service_close(instance->vchi_handle[i]); -+ LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]); -+ if (instance->vchi_handle[i]) -+ vchi_service_close(instance->vchi_handle[i]); - } - - kfree(instance); -+ LOG_ERR("%s: error\n", __func__); - - return NULL; - } -@@ -345,12 +362,13 @@ static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream) - { - static VCHI_INSTANCE_T vchi_instance; - static VCHI_CONNECTION_T *vchi_connection; -+ static int initted; - AUDIO_INSTANCE_T *instance = alsa_stream->instance; - int ret; - LOG_DBG(" .. IN\n"); - -- LOG_INFO("%s: start", __func__); -- //BUG_ON(instance); -+ LOG_INFO("%s: start\n", __func__); -+ BUG_ON(instance); - if (instance) { - LOG_ERR("%s: VCHI instance already open (%p)\n", - __func__, instance); -@@ -361,27 +379,30 @@ static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream) - } - - /* Initialize and create a VCHI connection */ -- ret = vchi_initialise(&vchi_instance); -- if (ret != 0) { -- LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n", -- __func__, ret); -- -- ret = -EIO; -- goto err_free_mem; -- } -- ret = vchi_connect(NULL, 0, vchi_instance); -- if (ret != 0) { -- LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n", -- __func__, ret); -- -- ret = -EIO; -- goto err_free_mem; -+ if (!initted) { -+ ret = vchi_initialise(&vchi_instance); -+ if (ret != 0) { -+ LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n", -+ __func__, ret); -+ -+ ret = -EIO; -+ goto err_free_mem; -+ } -+ ret = vchi_connect(NULL, 0, vchi_instance); -+ if (ret != 0) { -+ LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n", -+ __func__, ret); -+ -+ ret = -EIO; -+ goto err_free_mem; -+ } -+ initted = 1; - } - - /* Initialize an instance of the audio service */ - instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1); - -- if (instance == NULL /*|| audio_handle != instance */ ) { -+ if (instance == NULL) { - LOG_ERR("%s: failed to initialize audio service\n", __func__); - - ret = -EPERM; -@@ -414,6 +435,7 @@ int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream) - goto exit; - } - instance = alsa_stream->instance; -+ LOG_DBG(" instance (%p)\n", instance); - - if(mutex_lock_interruptible(&instance->vchi_mutex)) - { -@@ -518,22 +540,23 @@ int bcm2835_audio_set_ctls(bcm2835_chip_t * chip) - int i; - int ret = 0; - LOG_DBG(" .. IN\n"); -+ LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume); - - /* change ctls for all substreams */ - for (i = 0; i < MAX_SUBSTREAMS; i++) { - if (chip->avail_substreams & (1 << i)) { - if (!chip->alsa_stream[i]) - { -- LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams); -+ LOG_ERR(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams); - ret = 0; - } - else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */ - (chip->alsa_stream[i], chip) != 0) - { -- LOG_DBG("Couldn't set the controls for stream %d\n", i); -+ LOG_ERR("Couldn't set the controls for stream %d\n", i); - ret = -1; - } -- else LOG_DBG(" Controls set for stream %d\n", i); -+ else LOG_ERR(" Controls set for stream %d\n", i); - } - } - LOG_DBG(" .. OUT ret=%d\n", ret); -@@ -648,7 +671,7 @@ static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream) - VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); - - if (success != 0) { -- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", -+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", - __func__, success); - - ret = -1; -@@ -688,7 +711,7 @@ static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream) - VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); - - if (success != 0) { -- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", -+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", - __func__, success); - - ret = -1; -@@ -732,7 +755,7 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream) - VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); - - if (success != 0) { -- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", -+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", - __func__, success); - ret = -1; - goto unlock; -@@ -740,12 +763,12 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream) - - ret = wait_for_completion_interruptible(&instance->msg_avail_comp); - if (ret) { -- LOG_ERR("%s: failed on waiting for event (status=%d)", -+ LOG_ERR("%s: failed on waiting for event (status=%d)\n", - __func__, success); - goto unlock; - } - if (instance->result != 0) { -- LOG_ERR("%s: failed result (status=%d)", -+ LOG_ERR("%s: failed result (status=%d)\n", - __func__, instance->result); - - ret = -1; -@@ -803,7 +826,7 @@ int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream, - VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); - - if (success != 0) { -- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", -+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", - __func__, success); - - ret = -1; -@@ -832,7 +855,7 @@ int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream, - } - if (success != 0) { - LOG_ERR -- ("%s: failed on vchi_bulk_queue_transmit (status=%d)", -+ ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n", - __func__, success); - - ret = -1; -diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h -index 8c2fe26..0f71c5d 100755 ---- a/sound/arm/bcm2835.h -+++ b/sound/arm/bcm2835.h -@@ -110,6 +110,7 @@ typedef struct bcm2835_chip { - - unsigned int opened; - unsigned int spdif_status; -+ struct mutex audio_mutex; - } bcm2835_chip_t; - - typedef struct bcm2835_alsa_stream { --- -2.0.3 - - -From 08152c73bc62a18932912cc16814d7b4b7a74dac Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Sun, 13 Jul 2014 20:48:30 +0100 -Subject: [PATCH 67/81] Fix for ALSA driver crash - -Avoids an issue when closing and opening vchiq where a message can arrive before service handle has been written ---- - .../misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c | 7 ++++--- - drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c | 12 ++++++++---- - 2 files changed, 12 insertions(+), 7 deletions(-) - -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 5a4182e..25e7011 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 -@@ -288,11 +288,12 @@ VCHIQ_STATUS_T vchiq_open_service( - NULL); - - if (service) { -+ *phandle = service->handle; - status = vchiq_open_service_internal(service, current->pid); -- if (status == VCHIQ_SUCCESS) -- *phandle = service->handle; -- else -+ if (status != VCHIQ_SUCCESS) { - vchiq_remove_service(service->handle); -+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID; -+ } - } - - failed: -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -index a0b069d..bc27bea 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -@@ -636,6 +636,9 @@ int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, - { - VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; - SHIM_SERVICE_T *service = service_alloc(instance, setup); -+ -+ *handle = (VCHI_SERVICE_HANDLE_T)service; -+ - if (service) { - VCHIQ_SERVICE_PARAMS_T params; - VCHIQ_STATUS_T status; -@@ -652,11 +655,10 @@ int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, - if (status != VCHIQ_SUCCESS) { - service_free(service); - service = NULL; -+ *handle = NULL; - } - } - -- *handle = (VCHI_SERVICE_HANDLE_T)service; -- - return (service != NULL) ? 0 : -1; - } - EXPORT_SYMBOL(vchi_service_open); -@@ -667,6 +669,9 @@ int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle, - { - VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; - SHIM_SERVICE_T *service = service_alloc(instance, setup); -+ -+ *handle = (VCHI_SERVICE_HANDLE_T)service; -+ - if (service) { - VCHIQ_SERVICE_PARAMS_T params; - VCHIQ_STATUS_T status; -@@ -682,11 +687,10 @@ int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle, - if (status != VCHIQ_SUCCESS) { - service_free(service); - service = NULL; -+ *handle = NULL; - } - } - -- *handle = (VCHI_SERVICE_HANDLE_T)service; -- - return (service != NULL) ? 0 : -1; - } - EXPORT_SYMBOL(vchi_service_create); --- -2.0.3 - - -From fa4faf59ca69cf318206ae890c757c8ffb33434c Mon Sep 17 00:00:00 2001 +From ce7699bc76f43dd06b7c2fd8f7dcf488749b985a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 68/81] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 58/69] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- - drivers/hid/usbhid/hid-core.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) + drivers/hid/usbhid/hid-core.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c -index 7b88f4c..236a09b 100644 +index 7b88f4c..016a485 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -49,7 +49,7 @@ @@ -116557,17 +113525,18 @@ index 7b88f4c..236a09b 100644 module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); -@@ -1090,8 +1090,11 @@ static int usbhid_start(struct hid_device *hid) +@@ -1090,8 +1090,12 @@ static int usbhid_start(struct hid_device *hid) } /* Change the polling interval of mice. */ - if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0) - interval = hid_mousepoll_interval; -+ if (hid->collection->usage == HID_GD_MOUSE) -+ if (hid_mousepoll_interval != ~0) -+ interval = hid_mousepoll_interval; -+ else if (interval < 16) ++ if (hid->collection->usage == HID_GD_MOUSE) { ++ if (hid_mousepoll_interval == ~0 && interval < 16) + interval = 16; ++ else if (hid_mousepoll_interval != ~0 && hid_mousepoll_interval != 0) ++ interval = hid_mousepoll_interval; ++ } ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { @@ -116575,10 +113544,10 @@ index 7b88f4c..236a09b 100644 2.0.3 -From fe0c3d1105cfb2ef9fa131adc7e06c5e22f3dc8a Mon Sep 17 00:00:00 2001 +From 3d10b641de5751000a87e71432e577d2d824e1f2 Mon Sep 17 00:00:00 2001 From: notro Date: Fri, 18 Jul 2014 18:15:57 +0200 -Subject: [PATCH 69/81] BCM2708: DT: change 'axi' nodename to 'soc' +Subject: [PATCH 59/69] BCM2708: DT: change 'axi' nodename to 'soc' Change DT node named 'axi' to 'soc' so it matches ARCH_BCM2835. The VC4 bootloader fills in certain properties in the 'axi' subtree, @@ -116606,10 +113575,10 @@ index 3f884b3..e02e67b 100644 2.0.3 -From 04362dc54b6d73502b9cfac91589d5fa67b45731 Mon Sep 17 00:00:00 2001 +From 49928dfbd6cb8dd00dfc9d3a8f50c819e04b49c5 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 27 Jul 2014 20:12:58 +0200 -Subject: [PATCH 70/81] spi: bcm2708: add device tree support +Subject: [PATCH 60/69] spi: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins and spidev in .dts file. @@ -116698,7 +113667,7 @@ index e02e67b..ec1d006 100644 }; }; diff --git a/drivers/spi/spi-bcm2708.c b/drivers/spi/spi-bcm2708.c -index 0952f40..013611e 100644 +index 349d21f..041b5e2 100644 --- a/drivers/spi/spi-bcm2708.c +++ b/drivers/spi/spi-bcm2708.c @@ -512,6 +512,7 @@ static int bcm2708_spi_probe(struct platform_device *pdev) @@ -116731,10 +113700,10 @@ index 0952f40..013611e 100644 2.0.3 -From 64769a77a82521b10da01be8dd480b68dacec1ae Mon Sep 17 00:00:00 2001 +From a77d4f70ec50b92c8eaedf630da8e0061e28c587 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 27 Jul 2014 20:13:44 +0200 -Subject: [PATCH 71/81] BCM2708: don't register SPI controller when using DT +Subject: [PATCH 61/69] BCM2708: don't register SPI controller when using DT The device for the SPI controller is in the Device Tree. Only register the device when not using DT. @@ -116759,7 +113728,7 @@ index 05945d6..1f29d7d 100644 default y help diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 6929e2e..d227f9b 100644 +index 83277d1f..a4286e9 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -514,6 +514,7 @@ static struct platform_device bcm2708_alsa_devices[] = { @@ -116808,10 +113777,10 @@ index 6929e2e..d227f9b 100644 2.0.3 -From b38e7f90eb8739377845ef10dadb4988f7cbc5d6 Mon Sep 17 00:00:00 2001 +From 81c6766ab049b9742d5051c7368530ddd046bd28 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 27 Jul 2014 20:14:05 +0200 -Subject: [PATCH 72/81] spi: bcm2835: make driver available on ARCH_BCM2708 +Subject: [PATCH 62/69] spi: bcm2835: make driver available on ARCH_BCM2708 Make this driver available on ARCH_BCM2708 @@ -116821,7 +113790,7 @@ Signed-off-by: Noralf Tronnes 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig -index 6015c1e..fa74d1f 100644 +index cb20594..54aac0f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -76,7 +76,7 @@ config SPI_ATMEL @@ -116837,10 +113806,10 @@ index 6015c1e..fa74d1f 100644 2.0.3 -From 180e86958b5fcd8a0bac18b243bce065e0abc2fc Mon Sep 17 00:00:00 2001 +From dc2e3bb2614efe04e0874e510d73ab0deee576b3 Mon Sep 17 00:00:00 2001 From: notro Date: Tue, 29 Jul 2014 11:04:49 +0200 -Subject: [PATCH 73/81] i2c: bcm2708: add device tree support +Subject: [PATCH 63/69] i2c: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins in .dts file. @@ -117008,10 +113977,10 @@ index 8750634..728cb69 100644 2.0.3 -From 8aa024e493f5779b320ae116e834dcca989b95dc Mon Sep 17 00:00:00 2001 +From 0c53ad1f44d5a4bd77502d8147dfe6cb5fce1577 Mon Sep 17 00:00:00 2001 From: notro Date: Tue, 29 Jul 2014 11:05:18 +0200 -Subject: [PATCH 74/81] bcm2708: don't register i2c controllers when using DT +Subject: [PATCH 64/69] bcm2708: don't register i2c controllers when using DT The devices for the i2c controllers are in the Device Tree. Only register devices when not using DT. @@ -117022,7 +113991,7 @@ Signed-off-by: Noralf Tronnes 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index d227f9b..f67e552 100644 +index a4286e9..a19f54d 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -560,6 +560,7 @@ static struct spi_board_info bcm2708_spi_devices[] = { @@ -117056,10 +114025,10 @@ index d227f9b..f67e552 100644 2.0.3 -From 5cde34892b3eac8216baaf8f3f1ef137f09b65e9 Mon Sep 17 00:00:00 2001 +From ea8bed1550c93b7bf8e67ae6844f4a948904a942 Mon Sep 17 00:00:00 2001 From: notro Date: Tue, 29 Jul 2014 11:05:39 +0200 -Subject: [PATCH 75/81] i2c: bcm2835: make driver available on ARCH_BCM2708 +Subject: [PATCH 65/69] i2c: bcm2835: make driver available on ARCH_BCM2708 Make this driver available on ARCH_BCM2708 @@ -117069,7 +114038,7 @@ Signed-off-by: Noralf Tronnes 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig -index 09c620f..64e5e8a 100644 +index 6426811..73c9cfd 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -338,7 +338,7 @@ config I2C_AU1550 @@ -117085,1253 +114054,4587 @@ index 09c620f..64e5e8a 100644 2.0.3 -From 4e00e098889e969903d7ae61d4cbd0e4773a52af Mon Sep 17 00:00:00 2001 -From: Howard Mitchell -Date: Wed, 30 Jul 2014 10:02:00 +0100 -Subject: [PATCH 76/81] Revert "fix soc-core's inverse range and let IQaudIO - DAC use this fixed SOC_DOUBLE_R_RANGE_TLV support" +From b86f0c81a89528b7f26ca6c05dfa5b8b2aa2720c Mon Sep 17 00:00:00 2001 +From: Daniel Matuschek +Date: Fri, 25 Jul 2014 07:08:09 +0200 +Subject: [PATCH 66/69] Configure GPIOs for I2S based on revision/card settings +With RPi model B+, assignment of the I2S GPIO pins has changed. +This patch uses the board revision to auto-detect the GPIOs used +for I2S. It also allows sound card drivers to set the GPIOs that +should be used. This is especially important with the Compute +Module. --- - sound/soc/soc-core.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) + sound/soc/bcm/bcm2708-i2s.c | 51 +++++++++++++++++++++++++++++++++++++++------ + sound/soc/bcm/bcm2708-i2s.h | 35 +++++++++++++++++++++++++++++++ + 2 files changed, 80 insertions(+), 6 deletions(-) + create mode 100644 sound/soc/bcm/bcm2708-i2s.h -diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index 4d8917b..bf39f16 100644 ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -3058,8 +3058,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, +diff --git a/sound/soc/bcm/bcm2708-i2s.c b/sound/soc/bcm/bcm2708-i2s.c +index 9976571..905f076 100644 +--- a/sound/soc/bcm/bcm2708-i2s.c ++++ b/sound/soc/bcm/bcm2708-i2s.c +@@ -31,6 +31,8 @@ + * General Public License for more details. + */ - if (invert) - val = ((max - ucontrol->value.integer.value[0] + min) & mask); -- else -- val = (ucontrol->value.integer.value[0] & mask); -+ else -+ val = (ucontrol->value.integer.value[0] & mask); - val_mask = mask << shift; - val = val << shift; - -@@ -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); -- else -- val = (ucontrol->value.integer.value[1] & mask); -+ else -+ val = (ucontrol->value.integer.value[1] & mask); - val_mask = mask << shift; - val = val << shift; - --- -2.0.3 - - -From 6a4491eb889dccce1c0279cbfcb038158b4c3a91 Mon Sep 17 00:00:00 2001 -From: Howard Mitchell -Date: Wed, 30 Jul 2014 10:08:37 +0100 -Subject: [PATCH 77/81] Revert "Fix volsw_range functions so - SOC_DOUBLE_R_RANGE_TLV works." - ---- - sound/soc/soc-core.c | 22 ++++++++++++---------- - 1 file changed, 12 insertions(+), 10 deletions(-) - -diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index bf39f16..051c006 100644 ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -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; -- uinfo->value.integer.min = min; -- uinfo->value.integer.max = platform_max; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = platform_max - min; - - return 0; - } -@@ -3056,10 +3056,9 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, - unsigned int val, val_mask; - int ret; - -+ val = ((ucontrol->value.integer.value[0] + min) & mask); - if (invert) -- val = ((max - ucontrol->value.integer.value[0] + min) & mask); -- else -- val = (ucontrol->value.integer.value[0] & mask); -+ val = max - val; - val_mask = mask << shift; - val = val << shift; - -@@ -3068,10 +3067,9 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, - return ret; - - if (snd_soc_volsw_is_stereo(mc)) { -+ val = ((ucontrol->value.integer.value[1] + min) & mask); - if (invert) -- val = ((max - ucontrol->value.integer.value[1] + min) & mask); -- else -- val = (ucontrol->value.integer.value[1] & mask); -+ val = max - val; - val_mask = mask << shift; - val = val << shift; - -@@ -3109,14 +3107,18 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, - (snd_soc_read(codec, reg) >> shift) & mask; - if (invert) - ucontrol->value.integer.value[0] = -- max - ucontrol->value.integer.value[0] + min; -+ max - ucontrol->value.integer.value[0]; -+ ucontrol->value.integer.value[0] = -+ ucontrol->value.integer.value[0] - min; - - if (snd_soc_volsw_is_stereo(mc)) { - ucontrol->value.integer.value[1] = - (snd_soc_read(codec, rreg) >> shift) & mask; - if (invert) - ucontrol->value.integer.value[1] = -- max - ucontrol->value.integer.value[1] + min; -+ max - ucontrol->value.integer.value[1]; -+ ucontrol->value.integer.value[1] = -+ ucontrol->value.integer.value[1] - min; - } - - return 0; --- -2.0.3 - - -From 30c03d03f4ecb018b425a1c1969515af60b07dc9 Mon Sep 17 00:00:00 2001 -From: Howard Mitchell -Date: Wed, 30 Jul 2014 10:20:03 +0100 -Subject: [PATCH 78/81] Revert "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 -- - sound/soc/bcm/Makefile | 2 - - sound/soc/bcm/iqaudio-dac.c | 111 ----------------- - sound/soc/codecs/Kconfig | 4 - - sound/soc/codecs/Makefile | 2 - - sound/soc/codecs/pcm512x.c | 243 ++++++++++++-------------------------- - sound/soc/codecs/pcm512x.h | 143 +++++++++++++--------- - 9 files changed, 163 insertions(+), 372 deletions(-) - delete mode 100644 sound/soc/bcm/iqaudio-dac.c - -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 29fe486..9888fc9 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -751,7 +751,6 @@ CONFIG_SND_BCM2708_SOC_RPI_DAC=m - CONFIG_SND_SOC_I2C_AND_SPI=m - CONFIG_SND_SOC_PCM5102A=m - CONFIG_SND_SOC_PCM1794A=m --CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m - CONFIG_SOUND_PRIME=m - CONFIG_HIDRAW=y - CONFIG_HID_A4TECH=m -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index f67e552..da38492 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -674,22 +674,6 @@ static struct platform_device snd_pcm1794a_codec_device = { - }; - #endif - -- --#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE) --static struct platform_device snd_rpi_iqaudio_dac_device = { -- .name = "snd-rpi-iqaudio-dac", -- .id = 0, -- .num_resources = 0, --}; -- --// Use the actual device name rather than generic driver name --static struct i2c_board_info __initdata snd_pcm512x_i2c_devices[] = { -- { -- I2C_BOARD_INFO("pcm5122", 0x4c) -- }, --}; --#endif -- - int __init bcm_register_device(struct platform_device *pdev) - { - int ret; -@@ -855,12 +839,6 @@ void __init bcm2708_init(void) - bcm_register_device(&snd_pcm1794a_codec_device); - #endif - --#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE) -- bcm_register_device(&snd_rpi_iqaudio_dac_device); -- i2c_register_board_info(1, snd_pcm512x_i2c_devices, ARRAY_SIZE(snd_pcm512x_i2c_devices)); --#endif -- -- - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { - struct amba_device *d = amba_devs[i]; - amba_device_register(d, &iomem_resource); -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 84e4f27..e563dbc 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -39,10 +39,3 @@ config SND_BCM2708_SOC_RPI_DAC - select SND_SOC_PCM1794A - help - Say Y or M if you want to add support for RPi-DAC. -- --config SND_BCM2708_SOC_IQAUDIO_DAC -- tristate "Support for IQaudIO-DAC" -- depends on SND_BCM2708_SOC_I2S -- select SND_SOC_PCM512x -- help -- Say Y or M if you want to add support for IQaudIO-DAC. -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index d597fb0..826df7d 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -12,9 +12,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o - snd-soc-hifiberry-dac-objs := hifiberry_dac.o - snd-soc-hifiberry-digi-objs := hifiberry_digi.o - snd-soc-rpi-dac-objs := rpi-dac.o --snd-soc-iqaudio-dac-objs := iqaudio-dac.o - - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o --obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o -diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c -deleted file mode 100644 -index 515f044..0000000 ---- a/sound/soc/bcm/iqaudio-dac.c -+++ /dev/null -@@ -1,111 +0,0 @@ --/* -- * ASoC Driver for IQaudIO DAC -- * -- * Author: Florian Meier -- * Copyright 2013 -- * -- * 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 --#include --#include --#include --#include -- --static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd) --{ --// NOT USED struct snd_soc_codec *codec = rtd->codec; -- -- return 0; --} -- --static int snd_rpi_iqaudio_dac_hw_params(struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params) --{ -- struct snd_soc_pcm_runtime *rtd = substream->private_data; --// NOT USED struct snd_soc_dai *codec_dai = rtd->codec_dai; --// NOT USED struct snd_soc_codec *codec = rtd->codec; -- struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -- -- unsigned int sample_bits = -- snd_pcm_format_physical_width(params_format(params)); -- -- return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); --} -- --/* machine stream operations */ --static struct snd_soc_ops snd_rpi_iqaudio_dac_ops = { -- .hw_params = snd_rpi_iqaudio_dac_hw_params, --}; -- --static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = { --{ -- .name = "IQaudIO DAC", -- .stream_name = "IQaudIO DAC HiFi", -- .cpu_dai_name = "bcm2708-i2s.0", -- .codec_dai_name = "pcm512x-hifi", -- .platform_name = "bcm2708-i2s.0", -- .codec_name = "pcm512x.1-004c", -- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -- SND_SOC_DAIFMT_CBS_CFS, -- .ops = &snd_rpi_iqaudio_dac_ops, -- .init = snd_rpi_iqaudio_dac_init, --}, --}; -- --/* audio machine driver */ --static struct snd_soc_card snd_rpi_iqaudio_dac = { -- .name = "snd_rpi_iqaudio_dac", -- .dai_link = snd_rpi_iqaudio_dac_dai, -- .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai), --}; -- --static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) --{ -- int ret = 0; -- -- snd_rpi_iqaudio_dac.dev = &pdev->dev; -- ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); -- if (ret) -- dev_err(&pdev->dev, -- "snd_soc_register_card() failed: %d\n", ret); -- -- return ret; --} -- --static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev) --{ -- return snd_soc_unregister_card(&snd_rpi_iqaudio_dac); --} -- --static const struct of_device_id iqaudio_of_match[] = { -- { .compatible = "iqaudio,iqaudio-dac", }, -- {}, --}; -- --static struct platform_driver snd_rpi_iqaudio_dac_driver = { -- .driver = { -- .name = "snd-rpi-iqaudio-dac", -- .owner = THIS_MODULE, -- .of_match_table = iqaudio_of_match, -- }, -- .probe = snd_rpi_iqaudio_dac_probe, -- .remove = snd_rpi_iqaudio_dac_remove, --}; -- --module_platform_driver(snd_rpi_iqaudio_dac_driver); -- --MODULE_AUTHOR("Florian Meier "); --MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); --MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index b3a0488..54dec92 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -71,7 +71,6 @@ 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 -@@ -399,9 +398,6 @@ config SND_SOC_PCM1794A - config SND_SOC_PCM5102A - tristate - --config SND_SOC_PCM512x -- tristate -- - config SND_SOC_RT5631 - tristate - -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 95600ec..7f0eefa 100644 ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -60,7 +60,6 @@ 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 -@@ -214,7 +213,6 @@ 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 - obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o - 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 -index b669e15..4b4c0c7 100644 ---- a/sound/soc/codecs/pcm512x.c -+++ b/sound/soc/codecs/pcm512x.c -@@ -18,11 +18,9 @@ ++#include "bcm2708-i2s.h" ++ #include #include - #include --#include - #include - #include - #include --#include + #include +@@ -46,6 +48,8 @@ #include - #include - #include -@@ -30,7 +28,7 @@ - #include "pcm512x.h" + #include - #define PCM512x_NUM_SUPPLIES 3 --static const char *pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { -+static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { - "AVDD", - "DVDD", - "CPVDD", -@@ -66,22 +64,29 @@ 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_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 }, - }; - - static bool pcm512x_readable(struct device *dev, unsigned int reg) -@@ -141,9 +146,18 @@ 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: -- return false; -+ /* There are 256 raw register addresses */ -+ return reg < 0xff; - } - } - -@@ -159,17 +173,22 @@ 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: -- return false; -+ /* There are 256 raw register addresses */ -+ return reg < 0xff; - } - } - - 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 *pcm512x_dsp_program_texts[] = { -+static const char * const pcm512x_dsp_program_texts[] = { - "FIR interpolation with de-emphasis", - "Low latency IIR with de-emphasis", -+ "Fixed process flow", - "High attenuation with de-emphasis", - "Ringing-less low latency FIR", - }; -@@ -182,31 +201,31 @@ static const unsigned int pcm512x_dsp_program_values[] = { - 7, - }; - --static const SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, -- PCM512x_DSP_PROGRAM, 0, 0x1f, -- pcm512x_dsp_program_texts, -- pcm512x_dsp_program_values); -+static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, -+ PCM512x_DSP_PROGRAM, 0, 0x1f, -+ pcm512x_dsp_program_texts, -+ pcm512x_dsp_program_values); - --static const char *pcm512x_clk_missing_text[] = { -+static const char * const pcm512x_clk_missing_text[] = { - "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" - }; - - static const struct soc_enum pcm512x_clk_missing = -- SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 7, pcm512x_clk_missing_text); -+ SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 8, pcm512x_clk_missing_text); - --static const char *pcm512x_autom_text[] = { -+static const char * const pcm512x_autom_text[] = { - "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, 7, -+ SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8, - pcm512x_autom_text); - - static const struct soc_enum pcm512x_autom_r = -- SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 7, -+ SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, - pcm512x_autom_text); - --static const char *pcm512x_ramp_rate_text[] = { -+static const char * const pcm512x_ramp_rate_text[] = { - "1 sample/update", "2 samples/update", "4 samples/update", - "Immediate" - }; -@@ -223,7 +242,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 *pcm512x_ramp_step_text[] = { -+static const char * const pcm512x_ramp_step_text[] = { - "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" - }; - -@@ -239,10 +258,13 @@ 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, 40, 255, 1, digital_tlv), -+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("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, - PCM512x_RQMR_SHIFT, 1, 1), - -@@ -343,27 +365,32 @@ static struct snd_soc_codec_driver pcm512x_codec_driver = { - .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), - }; - --static const struct regmap_config pcm512x_regmap = { -+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, -+}; ++#include + -+const struct regmap_config pcm512x_regmap = { - .reg_bits = 8, - .val_bits = 8, + /* Clock registers */ + #define BCM2708_CLK_PCMCTL_REG 0x00 + #define BCM2708_CLK_PCMDIV_REG 0x04 +@@ -163,6 +167,9 @@ static const unsigned int bcm2708_clk_freq[BCM2708_CLK_SRC_HDMI+1] = { + #define BCM2708_DMA_DREQ_PCM_TX 2 + #define BCM2708_DMA_DREQ_PCM_RX 3 - .readable_reg = pcm512x_readable, - .volatile_reg = pcm512x_volatile, - -+ .ranges = &pcm512x_range, -+ .num_ranges = 1, ++/* I2S pin configuration */ ++static int bcm2708_i2s_gpio=BCM2708_I2S_GPIO_AUTO; + - .max_register = PCM512x_MAX_REGISTER, - .reg_defaults = pcm512x_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), - .cache_type = REGCACHE_RBTREE, + /* General device struct */ + struct bcm2708_i2s_dev { + struct device *dev; +@@ -174,6 +181,12 @@ struct bcm2708_i2s_dev { + struct regmap *clk_regmap; }; -+EXPORT_SYMBOL_GPL(pcm512x_regmap); --static const struct of_device_id pcm512x_of_match[] = { -- { .compatible = "ti,pcm5121", }, -- { .compatible = "ti,pcm5122", }, -- { } --}; --MODULE_DEVICE_TABLE(of, pcm512x_of_match); -- --static int pcm512x_probe(struct device *dev, struct regmap *regmap) -+int pcm512x_probe(struct device *dev, struct regmap *regmap) ++void bcm2708_i2s_set_gpio(int gpio) { ++ bcm2708_i2s_gpio=gpio; ++} ++EXPORT_SYMBOL(bcm2708_i2s_set_gpio); ++ ++ + static void bcm2708_i2s_start_clock(struct bcm2708_i2s_dev *dev) { - struct pcm512x_priv *pcm512x; - int i, ret; -@@ -463,8 +490,6 @@ static int pcm512x_probe(struct device *dev, struct regmap *regmap) - goto err_pm; - } - -- dev_info(dev, "Completed initialisation - pcm512x_probe"); -- - return 0; - - err_pm: -@@ -477,8 +502,9 @@ static int pcm512x_probe(struct device *dev, struct regmap *regmap) - pcm512x->supplies); - return ret; - } -+EXPORT_SYMBOL_GPL(pcm512x_probe); - --static void pcm512x_remove(struct device *dev) -+void pcm512x_remove(struct device *dev) - { - struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); - -@@ -489,8 +515,8 @@ static 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); -@@ -553,125 +579,10 @@ static int pcm512x_resume(struct device *dev) + /* Start the clock if in master mode */ +@@ -305,7 +318,6 @@ static int bcm2708_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai, return 0; } --// END OF PCM512x_suspend and resume calls TODO --*/ - --static const struct dev_pm_ops pcm512x_pm_ops = { -+const struct dev_pm_ops pcm512x_pm_ops = { - SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) - }; -- --#if IS_ENABLED(CONFIG_I2C) --static int pcm512x_i2c_probe(struct i2c_client *i2c, -- const struct i2c_device_id *id) --{ -- struct regmap *regmap; -- -- regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap); -- if (IS_ERR(regmap)) -- return PTR_ERR(regmap); -- -- return pcm512x_probe(&i2c->dev, regmap); --} -- --static int pcm512x_i2c_remove(struct i2c_client *i2c) --{ -- pcm512x_remove(&i2c->dev); -- return 0; --} -- --static const struct i2c_device_id pcm512x_i2c_id[] = { -- { "pcm5121", }, -- { "pcm5122", }, -- { } --}; --MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); -- --static struct i2c_driver pcm512x_i2c_driver = { -- .probe = pcm512x_i2c_probe, -- .remove = pcm512x_i2c_remove, -- .id_table = pcm512x_i2c_id, -- .driver = { -- .name = "pcm512x", -- .owner = THIS_MODULE, -- .of_match_table = pcm512x_of_match, -- .pm = &pcm512x_pm_ops, -- }, --}; --#endif -- --#if defined(CONFIG_SPI_MASTER) --static int pcm512x_spi_probe(struct spi_device *spi) --{ -- struct regmap *regmap; -- int ret; -- -- regmap = devm_regmap_init_spi(spi, &pcm512x_regmap); -- if (IS_ERR(regmap)) { -- ret = PTR_ERR(regmap); -- return ret; -- } -- -- return pcm512x_probe(&spi->dev, regmap); --} -- --static int pcm512x_spi_remove(struct spi_device *spi) --{ -- pcm512x_remove(&spi->dev); -- return 0; --} -- --static const struct spi_device_id pcm512x_spi_id[] = { -- { "pcm5121", }, -- { "pcm5122", }, -- { }, --}; --MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); -- --static struct spi_driver pcm512x_spi_driver = { -- .probe = pcm512x_spi_probe, -- .remove = pcm512x_spi_remove, -- .id_table = pcm512x_spi_id, -- .driver = { -- .name = "pcm512x", -- .owner = THIS_MODULE, -- .of_match_table = pcm512x_of_match, -- .pm = &pcm512x_pm_ops, -- }, --}; --#endif -- --static int __init pcm512x_modinit(void) --{ -- int ret = 0; -- --#if IS_ENABLED(CONFIG_I2C) -- ret = i2c_add_driver(&pcm512x_i2c_driver); -- if (ret) { -- printk(KERN_ERR "Failed to register pcm512x I2C driver: %d\n", -- ret); -- } --#endif --#if defined(CONFIG_SPI_MASTER) -- ret = spi_register_driver(&pcm512x_spi_driver); -- if (ret != 0) { -- printk(KERN_ERR "Failed to register pcm512x SPI driver: %d\n", -- ret); -- } --#endif -- return ret; --} --module_init(pcm512x_modinit); -- --static void __exit pcm512x_exit(void) --{ --#if IS_ENABLED(CONFIG_I2C) -- i2c_del_driver(&pcm512x_i2c_driver); --#endif --#if defined(CONFIG_SPI_MASTER) -- spi_unregister_driver(&pcm512x_spi_driver); --#endif --} --module_exit(pcm512x_exit); -+EXPORT_SYMBOL_GPL(pcm512x_pm_ops); + static void bcm2708_i2s_setup_gpio(void) + { + /* +@@ -318,14 +330,41 @@ static void bcm2708_i2s_setup_gpio(void) + #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) - MODULE_DESCRIPTION("ASoC PCM512x codec driver"); - MODULE_AUTHOR("Mark Brown "); -diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h -index b2f518e..6ee76aa 100644 ---- a/sound/soc/codecs/pcm512x.h -+++ b/sound/soc/codecs/pcm512x.h -@@ -17,66 +17,81 @@ - #ifndef _SND_SOC_PCM512X - #define _SND_SOC_PCM512X + unsigned int *gpio; +- int pin; ++ int pin,pinconfig,startpin,alt; ++ + gpio = ioremap(GPIO_BASE, SZ_16K); --#define PCM512x_PAGE_0_BASE 0 -+#include -+#include +- /* SPI is on GPIO 7..11 */ +- for (pin = 28; pin <= 31; pin++) { +- INP_GPIO(pin); /* set mode to GPIO input first */ +- SET_GPIO_ALT(pin, 2); /* set mode to ALT 0 */ ++ /* SPI is on different GPIOs on different boards */ ++ /* for Raspberry Pi B+, this is pin GPIO18-21, for original on 28-31 */ ++ if (bcm2708_i2s_gpio==BCM2708_I2S_GPIO_AUTO) { ++ if (system_rev >= 0x10) { ++ /* Model B+ */ ++ pinconfig=BCM2708_I2S_GPIO_PIN18; ++ } else { ++ /* original */ ++ pinconfig=BCM2708_I2S_GPIO_PIN28; ++ } ++ } else { ++ pinconfig=bcm2708_i2s_gpio; ++ } + -+#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 - --#define PCM512x_RESET (PCM512x_PAGE_0_BASE + 1) --#define PCM512x_POWER (PCM512x_PAGE_0_BASE + 2) --#define PCM512x_MUTE (PCM512x_PAGE_0_BASE + 3) --#define PCM512x_PLL_EN (PCM512x_PAGE_0_BASE + 4) --#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_0_BASE + 6) --#define PCM512x_DSP (PCM512x_PAGE_0_BASE + 7) --#define PCM512x_GPIO_EN (PCM512x_PAGE_0_BASE + 8) --#define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_0_BASE + 9) --#define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_0_BASE + 10) --#define PCM512x_MASTER_MODE (PCM512x_PAGE_0_BASE + 12) --#define PCM512x_PLL_REF (PCM512x_PAGE_0_BASE + 13) --#define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_0_BASE + 20) --#define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_0_BASE + 21) --#define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_0_BASE + 22) --#define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_0_BASE + 23) --#define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_0_BASE + 24) --#define PCM512x_DSP_CLKDIV (PCM512x_PAGE_0_BASE + 27) --#define PCM512x_DAC_CLKDIV (PCM512x_PAGE_0_BASE + 28) --#define PCM512x_NCP_CLKDIV (PCM512x_PAGE_0_BASE + 29) --#define PCM512x_OSR_CLKDIV (PCM512x_PAGE_0_BASE + 30) --#define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_0_BASE + 32) --#define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_0_BASE + 33) --#define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_0_BASE + 34) --#define PCM512x_IDAC_1 (PCM512x_PAGE_0_BASE + 35) --#define PCM512x_IDAC_2 (PCM512x_PAGE_0_BASE + 36) --#define PCM512x_ERROR_DETECT (PCM512x_PAGE_0_BASE + 37) --#define PCM512x_I2S_1 (PCM512x_PAGE_0_BASE + 40) --#define PCM512x_I2S_2 (PCM512x_PAGE_0_BASE + 41) --#define PCM512x_DAC_ROUTING (PCM512x_PAGE_0_BASE + 42) --#define PCM512x_DSP_PROGRAM (PCM512x_PAGE_0_BASE + 43) --#define PCM512x_CLKDET (PCM512x_PAGE_0_BASE + 44) --#define PCM512x_AUTO_MUTE (PCM512x_PAGE_0_BASE + 59) --#define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_0_BASE + 60) --#define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_0_BASE + 61) --#define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_0_BASE + 62) --#define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_0_BASE + 63) --#define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_0_BASE + 64) --#define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_0_BASE + 65) --#define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_0_BASE + 80) --#define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_0_BASE + 81) --#define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_0_BASE + 82) --#define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_0_BASE + 83) --#define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_0_BASE + 84) --#define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_0_BASE + 85) --#define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_0_BASE + 86) --#define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_0_BASE + 87) --#define PCM512x_OVERFLOW (PCM512x_PAGE_0_BASE + 90) --#define PCM512x_RATE_DET_1 (PCM512x_PAGE_0_BASE + 91) --#define PCM512x_RATE_DET_2 (PCM512x_PAGE_0_BASE + 92) --#define PCM512x_RATE_DET_3 (PCM512x_PAGE_0_BASE + 93) --#define PCM512x_RATE_DET_4 (PCM512x_PAGE_0_BASE + 94) --#define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_0_BASE + 108) --#define PCM512x_GPIN (PCM512x_PAGE_0_BASE + 119) --#define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_0_BASE + 120) -- --#define PCM512x_MAX_REGISTER (PCM512x_PAGE_0_BASE + 120) -+#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) ++ if (pinconfig==BCM2708_I2S_GPIO_PIN18) { ++ startpin=18; ++ alt=BCM2708_I2S_GPIO_PIN18_ALT; ++ } else if (pinconfig==BCM2708_I2S_GPIO_PIN28) { ++ startpin=28; ++ alt=BCM2708_I2S_GPIO_PIN28_ALT; ++ } else { ++ printk(KERN_INFO "Can't configure I2S GPIOs, unknown pin mode for I2S: %i\n",pinconfig); ++ return; ++ } + -+#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) ++ /* configure I2S pins to correct ALT mode */ ++ for (pin = startpin; pin <= startpin+3; pin++) { ++ INP_GPIO(pin); /* set mode to GPIO input first */ ++ SET_GPIO_ALT(pin, alt); /* set mode to ALT */ + } ++ + #undef INP_GPIO + #undef SET_GPIO_ALT + } +diff --git a/sound/soc/bcm/bcm2708-i2s.h b/sound/soc/bcm/bcm2708-i2s.h +new file mode 100644 +index 0000000..94fed6a +--- /dev/null ++++ b/sound/soc/bcm/bcm2708-i2s.h +@@ -0,0 +1,35 @@ ++/* ++ * I2S configuration for sound cards. ++ * ++ * Copyright (c) 2014 Daniel Matuschek ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ + -+#define PCM512x_CRAM_CTRL (PCM512x_PAGE_BASE(44) + 1) ++#ifndef BCM2708_I2S_H ++#define BCM2708_I2S_H + -+#define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(44) + 1) - - /* Page 0, Register 1 - reset */ - #define PCM512x_RSTR (1 << 0) -@@ -139,4 +154,18 @@ - #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 ++/* I2S pin assignment */ ++#define BCM2708_I2S_GPIO_AUTO 0 ++#define BCM2708_I2S_GPIO_PIN18 1 ++#define BCM2708_I2S_GPIO_PIN28 2 + -+/* Page 1, Register 7 - analog boost control */ -+#define PCM512x_AGBR_SHIFT 0 -+#define PCM512x_AGBL_SHIFT 4 ++/* Alt mode to enable I2S */ ++#define BCM2708_I2S_GPIO_PIN18_ALT 0 ++#define BCM2708_I2S_GPIO_PIN28_ALT 2 + -+extern const struct dev_pm_ops pcm512x_pm_ops; -+extern const struct regmap_config pcm512x_regmap; ++extern void bcm2708_i2s_set_gpio(int gpio); + -+int pcm512x_probe(struct device *dev, struct regmap *regmap); -+void pcm512x_remove(struct device *dev); -+ - #endif ++#endif -- 2.0.3 -From 0a5d48a65a72b4eed8da1b3e84a1ba4886d6552b Mon Sep 17 00:00:00 2001 -From: Gordon Garrity -Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 79/81] Add IQaudIO Sound Card support for Raspberry Pi +From 889929e30c5ce608411d40106e04dd120ffffb09 Mon Sep 17 00:00:00 2001 +From: P33M +Date: Thu, 24 Jul 2014 21:24:03 +0100 +Subject: [PATCH 67/69] usb: core: make overcurrent messages more prominent +Hub overcurrent messages are more serious than "debug". Increase loglevel. --- - arch/arm/configs/bcmrpi_defconfig | 1 + - arch/arm/mach-bcm2708/bcm2708.c | 22 ++++++++ - sound/soc/bcm/Kconfig | 7 +++ - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/iqaudio-dac.c | 111 ++++++++++++++++++++++++++++++++++++++ - 5 files changed, 143 insertions(+) - create mode 100644 sound/soc/bcm/iqaudio-dac.c + drivers/usb/core/hub.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 9888fc9..29fe486 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -751,6 +751,7 @@ CONFIG_SND_BCM2708_SOC_RPI_DAC=m - CONFIG_SND_SOC_I2C_AND_SPI=m - CONFIG_SND_SOC_PCM5102A=m - CONFIG_SND_SOC_PCM1794A=m -+CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m - CONFIG_SOUND_PRIME=m - CONFIG_HIDRAW=y - CONFIG_HID_A4TECH=m -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index da38492..f67e552 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -674,6 +674,22 @@ static struct platform_device snd_pcm1794a_codec_device = { - }; - #endif +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 0e950ad..6b004cf 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -4847,7 +4847,7 @@ static void port_event(struct usb_hub *hub, int port1) + if (portchange & USB_PORT_STAT_C_OVERCURRENT) { + u16 status = 0, unused; -+ -+#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE) -+static struct platform_device snd_rpi_iqaudio_dac_device = { -+ .name = "snd-rpi-iqaudio-dac", -+ .id = 0, -+ .num_resources = 0, -+}; -+ -+// Use the actual device name rather than generic driver name -+static struct i2c_board_info __initdata snd_pcm512x_i2c_devices[] = { -+ { -+ I2C_BOARD_INFO("pcm5122", 0x4c) -+ }, -+}; -+#endif -+ - int __init bcm_register_device(struct platform_device *pdev) - { - int ret; -@@ -839,6 +855,12 @@ void __init bcm2708_init(void) - bcm_register_device(&snd_pcm1794a_codec_device); - #endif - -+#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE) -+ bcm_register_device(&snd_rpi_iqaudio_dac_device); -+ i2c_register_board_info(1, snd_pcm512x_i2c_devices, ARRAY_SIZE(snd_pcm512x_i2c_devices)); -+#endif -+ -+ - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { - struct amba_device *d = amba_devs[i]; - amba_device_register(d, &iomem_resource); -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index e563dbc..c621a5e 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -39,3 +39,10 @@ config SND_BCM2708_SOC_RPI_DAC - select SND_SOC_PCM1794A - help - Say Y or M if you want to add support for RPi-DAC. -+ -+config SND_BCM2708_SOC_IQAUDIO_DAC -+ tristate "Support for IQaudIO-DAC" -+ depends on SND_BCM2708_SOC_I2S -+ select SND_SOC_PCM512x_I2C -+ help -+ Say Y or M if you want to add support for IQaudIO-DAC. -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 826df7d..d597fb0 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -12,7 +12,9 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o - snd-soc-hifiberry-dac-objs := hifiberry_dac.o - snd-soc-hifiberry-digi-objs := hifiberry_digi.o - snd-soc-rpi-dac-objs := rpi-dac.o -+snd-soc-iqaudio-dac-objs := iqaudio-dac.o - - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o -+obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o -diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +- dev_dbg(&port_dev->dev, "over-current change\n"); ++ dev_notice(&port_dev->dev, "over-current change\n"); + usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_C_OVER_CURRENT); + msleep(100); /* Cool down */ +-- +2.0.3 + + +From 31b51048cc569d29cb2d4dfff91090bd18f9e7e2 Mon Sep 17 00:00:00 2001 +From: Tim Gover +Date: Tue, 22 Jul 2014 15:41:04 +0100 +Subject: [PATCH 68/69] vcsm: VideoCore shared memory service for BCM2835 + +Add experimental support for the VideoCore shared memory service. +This allows user processes to allocate memory from VideoCore's +GPU relocatable heap and mmap the buffers. Additionally, the memory +handles can passed to other VideoCore services such as MMAL, OpenMax +and DispmanX + +TODO +* This driver was originally released for BCM28155 which has a different + cache architecture to BCM2835. Consequently, in this release only + uncached mappings are supported. However, there's no fundamental + reason which cached mappings cannot be support or BCM2835 +* More refactoring is required to remove the typedefs. +* Re-enable the some of the commented out debug-fs statistics which were + disabled when migrating code from proc-fs. +* There's a lot of code to support sharing of VCSM in order to support + Android. This could probably done more cleanly or perhaps just + removed. + +Signed-off-by: Tim Gover + +config: Disable VC_SM for now to fix hang with cutdown kernel +--- + arch/arm/mach-bcm2708/include/mach/vc_sm_defs.h | 181 ++ + arch/arm/mach-bcm2708/include/mach/vc_sm_knl.h | 55 + + arch/arm/mach-bcm2708/include/mach/vc_vchi_sm.h | 82 + + arch/arm/mach-bcm2708/include/mach/vmcs_sm_ioctl.h | 233 ++ + drivers/char/broadcom/Kconfig | 6 + + drivers/char/broadcom/Makefile | 1 + + drivers/char/broadcom/vc_sm/Makefile | 21 + + drivers/char/broadcom/vc_sm/vc_vchi_sm.c | 492 +++ + drivers/char/broadcom/vc_sm/vmcs_sm.c | 3163 ++++++++++++++++++++ + 9 files changed, 4234 insertions(+) + create mode 100644 arch/arm/mach-bcm2708/include/mach/vc_sm_defs.h + create mode 100644 arch/arm/mach-bcm2708/include/mach/vc_sm_knl.h + create mode 100644 arch/arm/mach-bcm2708/include/mach/vc_vchi_sm.h + create mode 100644 arch/arm/mach-bcm2708/include/mach/vmcs_sm_ioctl.h + create mode 100644 drivers/char/broadcom/vc_sm/Makefile + create mode 100644 drivers/char/broadcom/vc_sm/vc_vchi_sm.c + create mode 100644 drivers/char/broadcom/vc_sm/vmcs_sm.c + +diff --git a/arch/arm/mach-bcm2708/include/mach/vc_sm_defs.h b/arch/arm/mach-bcm2708/include/mach/vc_sm_defs.h new file mode 100644 -index 0000000..8d0e2ae +index 0000000..c4d5ff7 --- /dev/null -+++ b/sound/soc/bcm/iqaudio-dac.c -@@ -0,0 +1,111 @@ -+/* -+ * ASoC Driver for IQaudIO DAC -+ * -+ * Author: Florian Meier -+ * Copyright 2013 -+ * -+ * 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. -+ */ ++++ b/arch/arm/mach-bcm2708/include/mach/vc_sm_defs.h +@@ -0,0 +1,181 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ + -+#include -+#include ++#ifndef __VC_SM_DEFS_H__INCLUDED__ ++#define __VC_SM_DEFS_H__INCLUDED__ + -+#include -+#include -+#include -+#include -+#include ++/* FourCC code used for VCHI connection */ ++#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM") + -+static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd) ++/* Maximum message length */ ++#define VC_SM_MAX_MSG_LEN (sizeof(VC_SM_MSG_UNION_T) + \ ++ sizeof(VC_SM_MSG_HDR_T)) ++#define VC_SM_MAX_RSP_LEN (sizeof(VC_SM_MSG_UNION_T)) ++ ++/* Resource name maximum size */ ++#define VC_SM_RESOURCE_NAME 32 ++ ++/* All message types supported for HOST->VC direction */ ++typedef enum { ++ /* Allocate shared memory block */ ++ VC_SM_MSG_TYPE_ALLOC, ++ /* Lock allocated shared memory block */ ++ VC_SM_MSG_TYPE_LOCK, ++ /* Unlock allocated shared memory block */ ++ VC_SM_MSG_TYPE_UNLOCK, ++ /* Unlock allocated shared memory block, do not answer command */ ++ VC_SM_MSG_TYPE_UNLOCK_NOANS, ++ /* Free shared memory block */ ++ VC_SM_MSG_TYPE_FREE, ++ /* Resize a shared memory block */ ++ VC_SM_MSG_TYPE_RESIZE, ++ /* Walk the allocated shared memory block(s) */ ++ VC_SM_MSG_TYPE_WALK_ALLOC, ++ ++ /* A previously applied action will need to be reverted */ ++ VC_SM_MSG_TYPE_ACTION_CLEAN, ++ VC_SM_MSG_TYPE_MAX ++} VC_SM_MSG_TYPE; ++ ++/* Type of memory to be allocated */ ++typedef enum { ++ VC_SM_ALLOC_CACHED, ++ VC_SM_ALLOC_NON_CACHED, ++ ++} VC_SM_ALLOC_TYPE_T; ++ ++/* Message header for all messages in HOST->VC direction */ ++typedef struct { ++ int32_t type; ++ uint32_t trans_id; ++ uint8_t body[0]; ++ ++} VC_SM_MSG_HDR_T; ++ ++/* Request to allocate memory (HOST->VC) */ ++typedef struct { ++ /* type of memory to allocate */ ++ VC_SM_ALLOC_TYPE_T type; ++ /* byte amount of data to allocate per unit */ ++ uint32_t base_unit; ++ /* number of unit to allocate */ ++ uint32_t num_unit; ++ /* alignement to be applied on allocation */ ++ uint32_t alignement; ++ /* identity of who allocated this block */ ++ uint32_t allocator; ++ /* resource name (for easier tracking on vc side) */ ++ char name[VC_SM_RESOURCE_NAME]; ++ ++} VC_SM_ALLOC_T; ++ ++/* Result of a requested memory allocation (VC->HOST) */ ++typedef struct { ++ /* Transaction identifier */ ++ uint32_t trans_id; ++ ++ /* Resource handle */ ++ uint32_t res_handle; ++ /* Pointer to resource buffer */ ++ void *res_mem; ++ /* Resource base size (bytes) */ ++ uint32_t res_base_size; ++ /* Resource number */ ++ uint32_t res_num; ++ ++} VC_SM_ALLOC_RESULT_T; ++ ++/* Request to free a previously allocated memory (HOST->VC) */ ++typedef struct { ++ /* Resource handle (returned from alloc) */ ++ uint32_t res_handle; ++ /* Resource buffer (returned from alloc) */ ++ void *res_mem; ++ ++} VC_SM_FREE_T; ++ ++/* Request to lock a previously allocated memory (HOST->VC) */ ++typedef struct { ++ /* Resource handle (returned from alloc) */ ++ uint32_t res_handle; ++ /* Resource buffer (returned from alloc) */ ++ void *res_mem; ++ ++} VC_SM_LOCK_UNLOCK_T; ++ ++/* Request to resize a previously allocated memory (HOST->VC) */ ++typedef struct { ++ /* Resource handle (returned from alloc) */ ++ uint32_t res_handle; ++ /* Resource buffer (returned from alloc) */ ++ void *res_mem; ++ /* Resource *new* size requested (bytes) */ ++ uint32_t res_new_size; ++ ++} VC_SM_RESIZE_T; ++ ++/* Result of a requested memory lock (VC->HOST) */ ++typedef struct { ++ /* Transaction identifier */ ++ uint32_t trans_id; ++ ++ /* Resource handle */ ++ uint32_t res_handle; ++ /* Pointer to resource buffer */ ++ void *res_mem; ++ /* Pointer to former resource buffer if the memory ++ * was reallocated */ ++ void *res_old_mem; ++ ++} VC_SM_LOCK_RESULT_T; ++ ++/* Generic result for a request (VC->HOST) */ ++typedef struct { ++ /* Transaction identifier */ ++ uint32_t trans_id; ++ ++ int32_t success; ++ ++} VC_SM_RESULT_T; ++ ++/* Request to revert a previously applied action (HOST->VC) */ ++typedef struct { ++ /* Action of interest */ ++ VC_SM_MSG_TYPE res_action; ++ /* Transaction identifier for the action of interest */ ++ uint32_t action_trans_id; ++ ++} VC_SM_ACTION_CLEAN_T; ++ ++/* Request to remove all data associated with a given allocator (HOST->VC) */ ++typedef struct { ++ /* Allocator identifier */ ++ uint32_t allocator; ++ ++} VC_SM_FREE_ALL_T; ++ ++/* Union of ALL messages */ ++typedef union { ++ VC_SM_ALLOC_T alloc; ++ VC_SM_ALLOC_RESULT_T alloc_result; ++ VC_SM_FREE_T free; ++ VC_SM_ACTION_CLEAN_T action_clean; ++ VC_SM_RESIZE_T resize; ++ VC_SM_LOCK_RESULT_T lock_result; ++ VC_SM_RESULT_T result; ++ VC_SM_FREE_ALL_T free_all; ++ ++} VC_SM_MSG_UNION_T; ++ ++#endif /* __VC_SM_DEFS_H__INCLUDED__ */ +diff --git a/arch/arm/mach-bcm2708/include/mach/vc_sm_knl.h b/arch/arm/mach-bcm2708/include/mach/vc_sm_knl.h +new file mode 100644 +index 0000000..965f9a2 +--- /dev/null ++++ b/arch/arm/mach-bcm2708/include/mach/vc_sm_knl.h +@@ -0,0 +1,55 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#ifndef __VC_SM_KNL_H__INCLUDED__ ++#define __VC_SM_KNL_H__INCLUDED__ ++ ++#if !defined(__KERNEL__) ++#error "This interface is for kernel use only..." ++#endif ++ ++/* Type of memory to be locked (ie mapped) */ ++typedef enum { ++ VC_SM_LOCK_CACHED, ++ VC_SM_LOCK_NON_CACHED, ++ ++} VC_SM_LOCK_CACHE_MODE_T; ++ ++/* Allocate a shared memory handle and block. ++*/ ++int vc_sm_alloc(VC_SM_ALLOC_T *alloc, int *handle); ++ ++/* Free a previously allocated shared memory handle and block. ++*/ ++int vc_sm_free(int handle); ++ ++/* Lock a memory handle for use by kernel. ++*/ ++int vc_sm_lock(int handle, VC_SM_LOCK_CACHE_MODE_T mode, ++ long unsigned int *data); ++ ++/* Unlock a memory handle in use by kernel. ++*/ ++int vc_sm_unlock(int handle, int flush, int no_vc_unlock); ++ ++/* Get an internal resource handle mapped from the external one. ++*/ ++int vc_sm_int_handle(int handle); ++ ++/* Map a shared memory region for use by kernel. ++*/ ++int vc_sm_map(int handle, unsigned int sm_addr, VC_SM_LOCK_CACHE_MODE_T mode, ++ long unsigned int *data); ++ ++#endif /* __VC_SM_KNL_H__INCLUDED__ */ +diff --git a/arch/arm/mach-bcm2708/include/mach/vc_vchi_sm.h b/arch/arm/mach-bcm2708/include/mach/vc_vchi_sm.h +new file mode 100644 +index 0000000..5e279f5 +--- /dev/null ++++ b/arch/arm/mach-bcm2708/include/mach/vc_vchi_sm.h +@@ -0,0 +1,82 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#ifndef __VC_VCHI_SM_H__INCLUDED__ ++#define __VC_VCHI_SM_H__INCLUDED__ ++ ++#include "interface/vchi/vchi.h" ++ ++#include "vc_sm_defs.h" ++ ++/* Forward declare. ++*/ ++typedef struct sm_instance *VC_VCHI_SM_HANDLE_T; ++ ++/* Initialize the shared memory service, opens up vchi connection to talk to it. ++*/ ++VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance, ++ VCHI_CONNECTION_T **vchi_connections, ++ uint32_t num_connections); ++ ++/* Terminates the shared memory service. ++*/ ++int vc_vchi_sm_stop(VC_VCHI_SM_HANDLE_T *handle); ++ ++/* Ask the shared memory service to allocate some memory on videocre and ++** return the result of this allocation (which upon success will be a pointer ++** to some memory in videocore space). ++*/ ++int vc_vchi_sm_alloc(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_ALLOC_T *alloc, ++ VC_SM_ALLOC_RESULT_T *alloc_result, uint32_t *trans_id); ++ ++/* Ask the shared memory service to free up some memory that was previously ++** allocated by the vc_vchi_sm_alloc function call. ++*/ ++int vc_vchi_sm_free(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_FREE_T *free, uint32_t *trans_id); ++ ++/* Ask the shared memory service to lock up some memory that was previously ++** allocated by the vc_vchi_sm_alloc function call. ++*/ ++int vc_vchi_sm_lock(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_LOCK_UNLOCK_T *lock_unlock, ++ VC_SM_LOCK_RESULT_T *lock_result, uint32_t *trans_id); ++ ++/* Ask the shared memory service to unlock some memory that was previously ++** allocated by the vc_vchi_sm_alloc function call. ++*/ ++int vc_vchi_sm_unlock(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_LOCK_UNLOCK_T *lock_unlock, ++ uint32_t *trans_id, uint8_t wait_reply); ++ ++/* Ask the shared memory service to resize some memory that was previously ++** allocated by the vc_vchi_sm_alloc function call. ++*/ ++int vc_vchi_sm_resize(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_RESIZE_T *resize, uint32_t *trans_id); ++ ++/* Walk the allocated resources on the videocore side, the allocation will ++** show up in the log. This is purely for debug/information and takes no ++** specific actions. ++*/ ++int vc_vchi_sm_walk_alloc(VC_VCHI_SM_HANDLE_T handle); ++ ++/* Clean up following a previously interrupted action which left the system ++** in a bad state of some sort. ++*/ ++int vc_vchi_sm_clean_up(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_ACTION_CLEAN_T *action_clean); ++ ++#endif /* __VC_VCHI_SM_H__INCLUDED__ */ +diff --git a/arch/arm/mach-bcm2708/include/mach/vmcs_sm_ioctl.h b/arch/arm/mach-bcm2708/include/mach/vmcs_sm_ioctl.h +new file mode 100644 +index 0000000..42d0eb0 +--- /dev/null ++++ b/arch/arm/mach-bcm2708/include/mach/vmcs_sm_ioctl.h +@@ -0,0 +1,233 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++* ++*****************************************************************************/ ++ ++#if !defined(__VMCS_SM_IOCTL_H__INCLUDED__) ++#define __VMCS_SM_IOCTL_H__INCLUDED__ ++ ++/* ---- Include Files ---------------------------------------------------- */ ++ ++#if defined(__KERNEL__) ++#include /* Needed for standard types */ ++#else ++#include ++#endif ++ ++#include ++ ++/* ---- Constants and Types ---------------------------------------------- */ ++ ++#define VMCS_SM_RESOURCE_NAME 32 ++#define VMCS_SM_RESOURCE_NAME_DEFAULT "sm-host-resource" ++ ++/* Type define used to create unique IOCTL number */ ++#define VMCS_SM_MAGIC_TYPE 'I' ++ ++/* IOCTL commands */ ++enum vmcs_sm_cmd_e { ++ VMCS_SM_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */ ++ VMCS_SM_CMD_ALLOC_SHARE, ++ VMCS_SM_CMD_LOCK, ++ VMCS_SM_CMD_LOCK_CACHE, ++ VMCS_SM_CMD_UNLOCK, ++ VMCS_SM_CMD_RESIZE, ++ VMCS_SM_CMD_UNMAP, ++ VMCS_SM_CMD_FREE, ++ VMCS_SM_CMD_FLUSH, ++ VMCS_SM_CMD_INVALID, ++ ++ VMCS_SM_CMD_SIZE_USR_HANDLE, ++ VMCS_SM_CMD_CHK_USR_HANDLE, ++ ++ VMCS_SM_CMD_MAPPED_USR_HANDLE, ++ VMCS_SM_CMD_MAPPED_USR_ADDRESS, ++ VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR, ++ VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL, ++ VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL, ++ ++ VMCS_SM_CMD_VC_WALK_ALLOC, ++ VMCS_SM_CMD_HOST_WALK_MAP, ++ VMCS_SM_CMD_HOST_WALK_PID_ALLOC, ++ VMCS_SM_CMD_HOST_WALK_PID_MAP, ++ ++ VMCS_SM_CMD_LAST /* Do no delete */ ++}; ++ ++/* Cache type supported, conveniently matches the user space definition in ++** user-vcsm.h. ++*/ ++enum vmcs_sm_cache_e { ++ VMCS_SM_CACHE_NONE, ++ VMCS_SM_CACHE_HOST, ++ VMCS_SM_CACHE_VC, ++ VMCS_SM_CACHE_BOTH, ++}; ++ ++/* IOCTL Data structures */ ++struct vmcs_sm_ioctl_alloc { ++ /* user -> kernel */ ++ unsigned int size; ++ unsigned int num; ++ enum vmcs_sm_cache_e cached; ++ char name[VMCS_SM_RESOURCE_NAME]; ++ ++ /* kernel -> user */ ++ unsigned int handle; ++ /* unsigned int base_addr; */ ++}; ++ ++struct vmcs_sm_ioctl_alloc_share { ++ /* user -> kernel */ ++ unsigned int handle; ++ unsigned int size; ++}; ++ ++struct vmcs_sm_ioctl_free { ++ /* user -> kernel */ ++ unsigned int handle; ++ /* unsigned int base_addr; */ ++}; ++ ++struct vmcs_sm_ioctl_lock_unlock { ++ /* user -> kernel */ ++ unsigned int handle; ++ ++ /* kernel -> user */ ++ unsigned int addr; ++}; ++ ++struct vmcs_sm_ioctl_lock_cache { ++ /* user -> kernel */ ++ unsigned int handle; ++ enum vmcs_sm_cache_e cached; ++}; ++ ++struct vmcs_sm_ioctl_resize { ++ /* user -> kernel */ ++ unsigned int handle; ++ unsigned int new_size; ++ ++ /* kernel -> user */ ++ unsigned int old_size; ++}; ++ ++struct vmcs_sm_ioctl_map { ++ /* user -> kernel */ ++ /* and kernel -> user */ ++ unsigned int pid; ++ unsigned int handle; ++ unsigned int addr; ++ ++ /* kernel -> user */ ++ unsigned int size; ++}; ++ ++struct vmcs_sm_ioctl_walk { ++ /* user -> kernel */ ++ unsigned int pid; ++}; ++ ++struct vmcs_sm_ioctl_chk { ++ /* user -> kernel */ ++ unsigned int handle; ++ ++ /* kernel -> user */ ++ unsigned int addr; ++ unsigned int size; ++ enum vmcs_sm_cache_e cache; ++}; ++ ++struct vmcs_sm_ioctl_size { ++ /* user -> kernel */ ++ unsigned int handle; ++ ++ /* kernel -> user */ ++ unsigned int size; ++}; ++ ++struct vmcs_sm_ioctl_cache { ++ /* user -> kernel */ ++ unsigned int handle; ++ unsigned int addr; ++ unsigned int size; ++}; ++ ++/* IOCTL numbers */ ++#define VMCS_SM_IOCTL_MEM_ALLOC\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC,\ ++ struct vmcs_sm_ioctl_alloc) ++#define VMCS_SM_IOCTL_MEM_ALLOC_SHARE\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC_SHARE,\ ++ struct vmcs_sm_ioctl_alloc_share) ++#define VMCS_SM_IOCTL_MEM_LOCK\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK,\ ++ struct vmcs_sm_ioctl_lock_unlock) ++#define VMCS_SM_IOCTL_MEM_LOCK_CACHE\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK_CACHE,\ ++ struct vmcs_sm_ioctl_lock_cache) ++#define VMCS_SM_IOCTL_MEM_UNLOCK\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_UNLOCK,\ ++ struct vmcs_sm_ioctl_lock_unlock) ++#define VMCS_SM_IOCTL_MEM_RESIZE\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_RESIZE,\ ++ struct vmcs_sm_ioctl_resize) ++#define VMCS_SM_IOCTL_MEM_FREE\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FREE,\ ++ struct vmcs_sm_ioctl_free) ++#define VMCS_SM_IOCTL_MEM_FLUSH\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FLUSH,\ ++ struct vmcs_sm_ioctl_cache) ++#define VMCS_SM_IOCTL_MEM_INVALID\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_INVALID,\ ++ struct vmcs_sm_ioctl_cache) ++ ++#define VMCS_SM_IOCTL_SIZE_USR_HDL\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_SIZE_USR_HANDLE,\ ++ struct vmcs_sm_ioctl_size) ++#define VMCS_SM_IOCTL_CHK_USR_HDL\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CHK_USR_HANDLE,\ ++ struct vmcs_sm_ioctl_chk) ++ ++#define VMCS_SM_IOCTL_MAP_USR_HDL\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_HANDLE,\ ++ struct vmcs_sm_ioctl_map) ++#define VMCS_SM_IOCTL_MAP_USR_ADDRESS\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_ADDRESS,\ ++ struct vmcs_sm_ioctl_map) ++#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_ADDR\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,\ ++ struct vmcs_sm_ioctl_map) ++#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_HDL\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,\ ++ struct vmcs_sm_ioctl_map) ++#define VMCS_SM_IOCTL_MAP_VC_ADDR_FR_HDL\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,\ ++ struct vmcs_sm_ioctl_map) ++ ++#define VMCS_SM_IOCTL_VC_WALK_ALLOC\ ++ _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_VC_WALK_ALLOC) ++#define VMCS_SM_IOCTL_HOST_WALK_MAP\ ++ _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_MAP) ++#define VMCS_SM_IOCTL_HOST_WALK_PID_ALLOC\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_ALLOC,\ ++ struct vmcs_sm_ioctl_walk) ++#define VMCS_SM_IOCTL_HOST_WALK_PID_MAP\ ++ _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_MAP,\ ++ struct vmcs_sm_ioctl_walk) ++ ++/* ---- Variable Externs ------------------------------------------------- */ ++ ++/* ---- Function Prototypes ---------------------------------------------- */ ++ ++#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */ +diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig +index f089943..d4eb46d 100644 +--- a/drivers/char/broadcom/Kconfig ++++ b/drivers/char/broadcom/Kconfig +@@ -14,3 +14,9 @@ config BCM_VC_CMA + help + Helper for videocore CMA access. + ++config BCM_VC_SM ++ tristate "VMCS Shared Memory" ++ default n ++ help ++ Support for the VC shared memory on the Broadcom reference ++ design. Uses the VCHIQ stack. +diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile +index 13c5bca..0bf7fdf 100644 +--- a/drivers/char/broadcom/Makefile ++++ b/drivers/char/broadcom/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_BCM_VC_CMA) += vc_cma/ ++obj-$(CONFIG_BCM_VC_SM) += vc_sm/ +diff --git a/drivers/char/broadcom/vc_sm/Makefile b/drivers/char/broadcom/vc_sm/Makefile +new file mode 100644 +index 0000000..924a66b +--- /dev/null ++++ b/drivers/char/broadcom/vc_sm/Makefile +@@ -0,0 +1,21 @@ ++EXTRA_CFLAGS += -Wall -Wstrict-prototypes -Wno-trigraphs -O2 ++ ++EXTRA_CFLAGS += -I"./arch/arm/mach-bcm2708/include/mach" ++EXTRA_CFLAGS += -I"drivers/misc/vc04_services" ++EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchi" ++EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchiq_arm" ++EXTRA_CFLAGS += -I"$(srctree)/fs/" ++ ++EXTRA_CFLAGS += -DOS_ASSERT_FAILURE ++EXTRA_CFLAGS += -D__STDC_VERSION=199901L ++EXTRA_CFLAGS += -D__STDC_VERSION__=199901L ++EXTRA_CFLAGS += -D__VCCOREVER__=0 ++EXTRA_CFLAGS += -D__KERNEL__ ++EXTRA_CFLAGS += -D__linux__ ++EXTRA_CFLAGS += -Werror ++ ++obj-$(CONFIG_BCM_VC_SM) := vc-sm.o ++ ++vc-sm-objs := \ ++ vmcs_sm.o \ ++ vc_vchi_sm.o +diff --git a/drivers/char/broadcom/vc_sm/vc_vchi_sm.c b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c +new file mode 100644 +index 0000000..7c6ba1a +--- /dev/null ++++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c +@@ -0,0 +1,492 @@ ++/***************************************************************************** ++* Copyright 2011-2012 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++/* ---- Include Files ----------------------------------------------------- */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vc_vchi_sm.h" ++ ++#define VC_SM_VER 1 ++#define VC_SM_MIN_VER 0 ++ ++/* ---- Private Constants and Types -------------------------------------- */ ++ ++/* Command blocks come from a pool */ ++#define SM_MAX_NUM_CMD_RSP_BLKS 32 ++ ++struct sm_cmd_rsp_blk { ++ struct list_head head; /* To create lists */ ++ struct semaphore sema; /* To be signaled when the response is there */ ++ ++ uint16_t id; ++ uint16_t length; ++ ++ uint8_t msg[VC_SM_MAX_MSG_LEN]; ++ ++ uint32_t wait:1; ++ uint32_t sent:1; ++ uint32_t alloc:1; ++ ++}; ++ ++struct sm_instance { ++ uint32_t num_connections; ++ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS]; ++ struct task_struct *io_thread; ++ struct semaphore io_sema; ++ ++ uint32_t trans_id; ++ ++ struct mutex lock; ++ struct list_head cmd_list; ++ struct list_head rsp_list; ++ struct list_head dead_list; ++ ++ struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS]; ++ struct list_head free_list; ++ struct mutex free_lock; ++ struct semaphore free_sema; ++ ++}; ++ ++/* ---- Private Variables ------------------------------------------------ */ ++ ++/* ---- Private Function Prototypes -------------------------------------- */ ++ ++/* ---- Private Functions ------------------------------------------------ */ ++static struct ++sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance, ++ VC_SM_MSG_TYPE id, void *msg, ++ uint32_t size, int wait) +{ -+// NOT USED struct snd_soc_codec *codec = rtd->codec; ++ struct sm_cmd_rsp_blk *blk; ++ VC_SM_MSG_HDR_T *hdr; ++ ++ if (down_interruptible(&instance->free_sema)) { ++ blk = kmalloc(sizeof(*blk), GFP_KERNEL); ++ if (!blk) ++ return NULL; ++ ++ blk->alloc = 1; ++ sema_init(&blk->sema, 0); ++ } else { ++ mutex_lock(&instance->free_lock); ++ blk = ++ list_first_entry(&instance->free_list, ++ struct sm_cmd_rsp_blk, head); ++ list_del(&blk->head); ++ mutex_unlock(&instance->free_lock); ++ } ++ ++ blk->sent = 0; ++ blk->wait = wait; ++ blk->length = sizeof(*hdr) + size; ++ ++ hdr = (VC_SM_MSG_HDR_T *) blk->msg; ++ hdr->type = id; ++ mutex_lock(&instance->lock); ++ hdr->trans_id = blk->id = ++instance->trans_id; ++ mutex_unlock(&instance->lock); ++ ++ if (size) ++ memcpy(hdr->body, msg, size); ++ ++ return blk; ++} ++ ++static void ++vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk) ++{ ++ if (blk->alloc) { ++ kfree(blk); ++ return; ++ } ++ ++ mutex_lock(&instance->free_lock); ++ list_add(&blk->head, &instance->free_list); ++ mutex_unlock(&instance->free_lock); ++ up(&instance->free_sema); ++} ++ ++static int vc_vchi_sm_videocore_io(void *arg) ++{ ++ struct sm_instance *instance = arg; ++ struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp; ++ VC_SM_RESULT_T *reply; ++ uint32_t reply_len; ++ int32_t status; ++ int svc_use = 1; ++ ++ while (1) { ++ if (svc_use) ++ vchi_service_release(instance->vchi_handle[0]); ++ svc_use = 0; ++ if (!down_interruptible(&instance->io_sema)) { ++ vchi_service_use(instance->vchi_handle[0]); ++ svc_use = 1; ++ ++ do { ++ unsigned int flags; ++ /* ++ * Get new command and move it to response list ++ */ ++ mutex_lock(&instance->lock); ++ if (list_empty(&instance->cmd_list)) { ++ /* no more commands to process */ ++ mutex_unlock(&instance->lock); ++ break; ++ } ++ cmd = ++ list_first_entry(&instance->cmd_list, ++ struct sm_cmd_rsp_blk, ++ head); ++ list_move(&cmd->head, &instance->rsp_list); ++ cmd->sent = 1; ++ mutex_unlock(&instance->lock); ++ ++ /* Send the command */ ++ flags = VCHI_FLAGS_BLOCK_UNTIL_QUEUED; ++ status = vchi_msg_queue( ++ instance->vchi_handle[0], ++ cmd->msg, cmd->length, ++ flags, NULL); ++ if (status) { ++ pr_err("%s: failed to queue message (%d)", ++ __func__, status); ++ } ++ ++ /* If no reply is needed then we're done */ ++ if (!cmd->wait) { ++ mutex_lock(&instance->lock); ++ list_del(&cmd->head); ++ mutex_unlock(&instance->lock); ++ vc_vchi_cmd_delete(instance, cmd); ++ continue; ++ } ++ ++ if (status) { ++ up(&cmd->sema); ++ continue; ++ } ++ ++ } while (1); ++ ++ while (!vchi_msg_peek ++ (instance->vchi_handle[0], (void **)&reply, ++ &reply_len, VCHI_FLAGS_NONE)) { ++ mutex_lock(&instance->lock); ++ list_for_each_entry(cmd, &instance->rsp_list, ++ head) { ++ if (cmd->id == reply->trans_id) ++ break; ++ } ++ mutex_unlock(&instance->lock); ++ ++ if (&cmd->head == &instance->rsp_list) { ++ pr_debug("%s: received response %u, throw away...", ++ __func__, reply->trans_id); ++ } else if (reply_len > sizeof(cmd->msg)) { ++ pr_err("%s: reply too big (%u) %u, throw away...", ++ __func__, reply_len, ++ reply->trans_id); ++ } else { ++ memcpy(cmd->msg, reply, reply_len); ++ up(&cmd->sema); ++ } ++ ++ vchi_msg_remove(instance->vchi_handle[0]); ++ } ++ ++ /* Go through the dead list and free them */ ++ mutex_lock(&instance->lock); ++ list_for_each_entry_safe(cmd, cmd_tmp, ++ &instance->dead_list, head) { ++ list_del(&cmd->head); ++ vc_vchi_cmd_delete(instance, cmd); ++ } ++ mutex_unlock(&instance->lock); ++ } ++ } + + return 0; +} + -+static int snd_rpi_iqaudio_dac_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) ++static void vc_sm_vchi_callback(void *param, ++ const VCHI_CALLBACK_REASON_T reason, ++ void *msg_handle) +{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+// NOT USED struct snd_soc_dai *codec_dai = rtd->codec_dai; -+// NOT USED struct snd_soc_codec *codec = rtd->codec; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ struct sm_instance *instance = param; + -+ unsigned int sample_bits = -+ snd_pcm_format_physical_width(params_format(params)); ++ (void)msg_handle; + -+ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); ++ switch (reason) { ++ case VCHI_CALLBACK_MSG_AVAILABLE: ++ up(&instance->io_sema); ++ break; ++ ++ case VCHI_CALLBACK_SERVICE_CLOSED: ++ pr_info("%s: service CLOSED!!", __func__); ++ default: ++ break; ++ } +} + -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_iqaudio_dac_ops = { -+ .hw_params = snd_rpi_iqaudio_dac_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = { ++VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance, ++ VCHI_CONNECTION_T **vchi_connections, ++ uint32_t num_connections) +{ -+ .name = "IQaudIO DAC", -+ .stream_name = "IQaudIO DAC HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "pcm512x-hifi", -+ .platform_name = "bcm2708-i2s.0", -+ .codec_name = "pcm512x.1-004c", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_iqaudio_dac_ops, -+ .init = snd_rpi_iqaudio_dac_init, -+}, -+}; ++ uint32_t i; ++ struct sm_instance *instance; ++ int status; + -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_iqaudio_dac = { -+ .name = "IQaudIODAC", -+ .dai_link = snd_rpi_iqaudio_dac_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai), -+}; ++ pr_debug("%s: start", __func__); + -+static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) ++ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) { ++ pr_err("%s: unsupported number of connections %u (max=%u)", ++ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS); ++ ++ goto err_null; ++ } ++ /* Allocate memory for this instance */ ++ instance = kzalloc(sizeof(*instance), GFP_KERNEL); ++ ++ /* Misc initialisations */ ++ mutex_init(&instance->lock); ++ sema_init(&instance->io_sema, 0); ++ INIT_LIST_HEAD(&instance->cmd_list); ++ INIT_LIST_HEAD(&instance->rsp_list); ++ INIT_LIST_HEAD(&instance->dead_list); ++ INIT_LIST_HEAD(&instance->free_list); ++ sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS); ++ mutex_init(&instance->free_lock); ++ for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) { ++ sema_init(&instance->free_blk[i].sema, 0); ++ list_add(&instance->free_blk[i].head, &instance->free_list); ++ } ++ ++ /* Open the VCHI service connections */ ++ instance->num_connections = num_connections; ++ for (i = 0; i < num_connections; i++) { ++ SERVICE_CREATION_T params = { ++ VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER), ++ VC_SM_SERVER_NAME, ++ vchi_connections[i], ++ 0, ++ 0, ++ vc_sm_vchi_callback, ++ instance, ++ 0, ++ 0, ++ 0, ++ }; ++ ++ status = vchi_service_open(vchi_instance, ++ ¶ms, &instance->vchi_handle[i]); ++ if (status) { ++ pr_err("%s: failed to open VCHI service (%d)", ++ __func__, status); ++ ++ goto err_close_services; ++ } ++ } ++ ++ /* Create the thread which takes care of all io to/from videoocore. */ ++ instance->io_thread = kthread_create(&vc_vchi_sm_videocore_io, ++ (void *)instance, "SMIO"); ++ if (instance->io_thread == NULL) { ++ pr_err("%s: failed to create SMIO thread", __func__); ++ ++ goto err_close_services; ++ } ++ set_user_nice(instance->io_thread, -10); ++ wake_up_process(instance->io_thread); ++ ++ pr_debug("%s: success - instance 0x%x", __func__, (unsigned)instance); ++ return instance; ++ ++err_close_services: ++ for (i = 0; i < instance->num_connections; i++) { ++ if (instance->vchi_handle[i] != NULL) ++ vchi_service_close(instance->vchi_handle[i]); ++ } ++ kfree(instance); ++err_null: ++ pr_debug("%s: FAILED", __func__); ++ return NULL; ++} ++ ++int vc_vchi_sm_stop(VC_VCHI_SM_HANDLE_T *handle) +{ -+ int ret = 0; ++ struct sm_instance *instance; ++ uint32_t i; + -+ snd_rpi_iqaudio_dac.dev = &pdev->dev; -+ ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); -+ if (ret) -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); ++ if (handle == NULL) { ++ pr_err("%s: invalid pointer to handle %p", __func__, handle); ++ goto lock; ++ } ++ ++ if (*handle == NULL) { ++ pr_err("%s: invalid handle %p", __func__, *handle); ++ goto lock; ++ } ++ ++ instance = *handle; ++ ++ /* Close all VCHI service connections */ ++ for (i = 0; i < instance->num_connections; i++) { ++ int32_t success; ++ vchi_service_use(instance->vchi_handle[i]); ++ ++ success = vchi_service_close(instance->vchi_handle[i]); ++ } ++ ++ kfree(instance); ++ ++ *handle = NULL; ++ return 0; ++ ++lock: ++ return -EINVAL; ++} ++ ++int vc_vchi_sm_send_msg(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_MSG_TYPE msg_id, ++ void *msg, uint32_t msg_size, ++ void *result, uint32_t result_size, ++ uint32_t *cur_trans_id, uint8_t wait_reply) ++{ ++ int status = 0; ++ struct sm_instance *instance = handle; ++ struct sm_cmd_rsp_blk *cmd_blk; ++ ++ if (handle == NULL) { ++ pr_err("%s: invalid handle", __func__); ++ return -EINVAL; ++ } ++ if (msg == NULL) { ++ pr_err("%s: invalid msg pointer", __func__); ++ return -EINVAL; ++ } ++ ++ cmd_blk = ++ vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply); ++ if (cmd_blk == NULL) { ++ pr_err("[%s]: failed to allocate global tracking resource", ++ __func__); ++ return -ENOMEM; ++ } ++ ++ if (cur_trans_id != NULL) ++ *cur_trans_id = cmd_blk->id; ++ ++ mutex_lock(&instance->lock); ++ list_add_tail(&cmd_blk->head, &instance->cmd_list); ++ mutex_unlock(&instance->lock); ++ up(&instance->io_sema); ++ ++ if (!wait_reply) ++ /* We're done */ ++ return 0; ++ ++ /* Wait for the response */ ++ if (down_interruptible(&cmd_blk->sema)) { ++ mutex_lock(&instance->lock); ++ if (!cmd_blk->sent) { ++ list_del(&cmd_blk->head); ++ mutex_unlock(&instance->lock); ++ vc_vchi_cmd_delete(instance, cmd_blk); ++ return -ENXIO; ++ } ++ mutex_unlock(&instance->lock); ++ ++ mutex_lock(&instance->lock); ++ list_move(&cmd_blk->head, &instance->dead_list); ++ mutex_unlock(&instance->lock); ++ up(&instance->io_sema); ++ return -EINTR; /* We're done */ ++ } ++ ++ if (result && result_size) { ++ memcpy(result, cmd_blk->msg, result_size); ++ } else { ++ VC_SM_RESULT_T *res = (VC_SM_RESULT_T *) cmd_blk->msg; ++ status = (res->success == 0) ? 0 : -ENXIO; ++ } ++ ++ mutex_lock(&instance->lock); ++ list_del(&cmd_blk->head); ++ mutex_unlock(&instance->lock); ++ vc_vchi_cmd_delete(instance, cmd_blk); ++ return status; ++} ++ ++int vc_vchi_sm_alloc(VC_VCHI_SM_HANDLE_T handle, VC_SM_ALLOC_T *msg, ++ VC_SM_ALLOC_RESULT_T *result, uint32_t *cur_trans_id) ++{ ++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_ALLOC, ++ msg, sizeof(*msg), result, sizeof(*result), ++ cur_trans_id, 1); ++} ++ ++int vc_vchi_sm_free(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_FREE_T *msg, uint32_t *cur_trans_id) ++{ ++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_FREE, ++ msg, sizeof(*msg), 0, 0, cur_trans_id, 0); ++} ++ ++int vc_vchi_sm_lock(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_LOCK_UNLOCK_T *msg, ++ VC_SM_LOCK_RESULT_T *result, uint32_t *cur_trans_id) ++{ ++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_LOCK, ++ msg, sizeof(*msg), result, sizeof(*result), ++ cur_trans_id, 1); ++} ++ ++int vc_vchi_sm_unlock(VC_VCHI_SM_HANDLE_T handle, ++ VC_SM_LOCK_UNLOCK_T *msg, ++ uint32_t *cur_trans_id, uint8_t wait_reply) ++{ ++ return vc_vchi_sm_send_msg(handle, wait_reply ? ++ VC_SM_MSG_TYPE_UNLOCK : ++ VC_SM_MSG_TYPE_UNLOCK_NOANS, msg, ++ sizeof(*msg), 0, 0, cur_trans_id, ++ wait_reply); ++} ++ ++int vc_vchi_sm_resize(VC_VCHI_SM_HANDLE_T handle, VC_SM_RESIZE_T *msg, ++ uint32_t *cur_trans_id) ++{ ++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_RESIZE, ++ msg, sizeof(*msg), 0, 0, cur_trans_id, 1); ++} ++ ++int vc_vchi_sm_walk_alloc(VC_VCHI_SM_HANDLE_T handle) ++{ ++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_WALK_ALLOC, ++ 0, 0, 0, 0, 0, 0); ++} ++ ++int vc_vchi_sm_clean_up(VC_VCHI_SM_HANDLE_T handle, VC_SM_ACTION_CLEAN_T *msg) ++{ ++ return vc_vchi_sm_send_msg(handle, VC_SM_MSG_TYPE_ACTION_CLEAN, ++ msg, sizeof(*msg), 0, 0, 0, 0); ++} +diff --git a/drivers/char/broadcom/vc_sm/vmcs_sm.c b/drivers/char/broadcom/vc_sm/vmcs_sm.c +new file mode 100644 +index 0000000..da1c523 +--- /dev/null ++++ b/drivers/char/broadcom/vc_sm/vmcs_sm.c +@@ -0,0 +1,3163 @@ ++/***************************************************************************** ++* Copyright 2011-2012 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++/* ---- Include Files ----------------------------------------------------- */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "vchiq_connected.h" ++#include "vc_vchi_sm.h" ++ ++#include ++#include "vc_sm_knl.h" ++ ++/* ---- Private Constants and Types --------------------------------------- */ ++ ++#define DEVICE_NAME "vcsm" ++#define DEVICE_MINOR 0 ++ ++#define VC_SM_DIR_ROOT_NAME "vc-smem" ++#define VC_SM_DIR_ALLOC_NAME "alloc" ++#define VC_SM_STATE "state" ++#define VC_SM_STATS "statistics" ++#define VC_SM_RESOURCES "resources" ++#define VC_SM_DEBUG "debug" ++#define VC_SM_WRITE_BUF_SIZE 128 ++ ++/* Statistics tracked per resource and globally. ++*/ ++enum SM_STATS_T { ++ /* Attempt. */ ++ ALLOC, ++ FREE, ++ LOCK, ++ UNLOCK, ++ MAP, ++ FLUSH, ++ INVALID, ++ ++ END_ATTEMPT, ++ ++ /* Failure. */ ++ ALLOC_FAIL, ++ FREE_FAIL, ++ LOCK_FAIL, ++ UNLOCK_FAIL, ++ MAP_FAIL, ++ FLUSH_FAIL, ++ INVALID_FAIL, ++ ++ END_ALL, ++ ++}; ++ ++static const char *const sm_stats_human_read[] = { ++ "Alloc", ++ "Free", ++ "Lock", ++ "Unlock", ++ "Map", ++ "Cache Flush", ++ "Cache Invalidate", ++}; ++ ++typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v); ++struct SM_PDE_T { ++ VC_SM_SHOW show; /* Debug fs function hookup. */ ++ struct dentry *dir_entry; /* Debug fs directory entry. */ ++ void *priv_data; /* Private data */ ++ ++}; ++ ++/* Single resource allocation tracked for all devices. ++*/ ++struct sm_mmap { ++ struct list_head map_list; /* Linked list of maps. */ ++ ++ struct SM_RESOURCE_T *resource; /* Pointer to the resource. */ ++ ++ pid_t res_pid; /* PID owning that resource. */ ++ unsigned int res_vc_hdl; /* Resource handle (videocore). */ ++ unsigned int res_usr_hdl; /* Resource handle (user). */ ++ ++ long unsigned int res_addr; /* Mapped virtual address. */ ++ struct vm_area_struct *vma; /* VM area for this mapping. */ ++ unsigned int ref_count; /* Reference count to this vma. */ ++ ++ /* Used to link maps associated with a resource. */ ++ struct list_head resource_map_list; ++}; ++ ++/* Single resource allocation tracked for each opened device. ++*/ ++struct SM_RESOURCE_T { ++ struct list_head resource_list; /* List of resources. */ ++ struct list_head global_resource_list; /* Global list of resources. */ ++ ++ pid_t pid; /* PID owning that resource. */ ++ uint32_t res_guid; /* Unique identifier. */ ++ uint32_t lock_count; /* Lock count for this resource. */ ++ uint32_t ref_count; /* Ref count for this resource. */ ++ ++ uint32_t res_handle; /* Resource allocation handle. */ ++ void *res_base_mem; /* Resource base memory address. */ ++ uint32_t res_size; /* Resource size allocated. */ ++ enum vmcs_sm_cache_e res_cached; /* Resource cache type. */ ++ struct SM_RESOURCE_T *res_shared; /* Shared resource */ ++ ++ enum SM_STATS_T res_stats[END_ALL]; /* Resource statistics. */ ++ ++ uint8_t map_count; /* Counter of mappings for this resource. */ ++ struct list_head map_list; /* Maps associated with a resource. */ ++ ++ struct SM_PRIV_DATA_T *private; ++}; ++ ++/* Private file data associated with each opened device. ++*/ ++struct SM_PRIV_DATA_T { ++ struct list_head resource_list; /* List of resources. */ ++ ++ pid_t pid; /* PID of creator. */ ++ ++ struct dentry *dir_pid; /* Debug fs entries root. */ ++ struct SM_PDE_T dir_stats; /* Debug fs entries statistics sub-tree. */ ++ struct SM_PDE_T dir_res; /* Debug fs resource sub-tree. */ ++ ++ int restart_sys; /* Tracks restart on interrupt. */ ++ VC_SM_MSG_TYPE int_action; /* Interrupted action. */ ++ uint32_t int_trans_id; /* Interrupted transaction. */ ++ ++}; ++ ++/* Global state information. ++*/ ++struct SM_STATE_T { ++ VC_VCHI_SM_HANDLE_T sm_handle; /* Handle for videocore service. */ ++ struct dentry *dir_root; /* Debug fs entries root. */ ++ struct dentry *dir_alloc; /* Debug fs entries allocations. */ ++ struct SM_PDE_T dir_stats; /* Debug fs entries statistics sub-tree. */ ++ struct SM_PDE_T dir_state; /* Debug fs entries state sub-tree. */ ++ struct dentry *debug; /* Debug fs entries debug. */ ++ ++ struct mutex map_lock; /* Global map lock. */ ++ struct list_head map_list; /* List of maps. */ ++ struct list_head resource_list; /* List of resources. */ ++ ++ enum SM_STATS_T deceased[END_ALL]; /* Natural termination stats. */ ++ enum SM_STATS_T terminated[END_ALL]; /* Forced termination stats. */ ++ uint32_t res_deceased_cnt; /* Natural termination counter. */ ++ uint32_t res_terminated_cnt; /* Forced termination counter. */ ++ ++ struct cdev sm_cdev; /* Device. */ ++ dev_t sm_devid; /* Device identifier. */ ++ struct class *sm_class; /* Class. */ ++ struct device *sm_dev; /* Device. */ ++ ++ struct SM_PRIV_DATA_T *data_knl; /* Kernel internal data tracking. */ ++ ++ struct mutex lock; /* Global lock. */ ++ uint32_t guid; /* GUID (next) tracker. */ ++ ++}; ++ ++/* ---- Private Variables ----------------------------------------------- */ ++ ++static struct SM_STATE_T *sm_state; ++static int sm_inited; ++ ++static const char *const sm_cache_map_vector[] = { ++ "(null)", ++ "host", ++ "videocore", ++ "host+videocore", ++}; ++ ++/* ---- Private Function Prototypes -------------------------------------- */ ++ ++/* ---- Private Functions ------------------------------------------------ */ ++ ++static inline unsigned vcaddr_to_pfn(unsigned long vc_addr) ++{ ++ unsigned long pfn = vc_addr & 0x3FFFFFFF; ++ pfn += mm_vc_mem_phys_addr; ++ pfn >>= PAGE_SHIFT; ++ return pfn; ++} ++ ++/* Carries over to the state statistics the statistics once owned by a deceased ++** resource. ++*/ ++static void vc_sm_resource_deceased(struct SM_RESOURCE_T *p_res, int terminated) ++{ ++ if (sm_state != NULL) { ++ if (p_res != NULL) { ++ int ix; ++ ++ if (terminated) ++ sm_state->res_terminated_cnt++; ++ else ++ sm_state->res_deceased_cnt++; ++ ++ for (ix = 0; ix < END_ALL; ix++) { ++ if (terminated) ++ sm_state->terminated[ix] += ++ p_res->res_stats[ix]; ++ else ++ sm_state->deceased[ix] += ++ p_res->res_stats[ix]; ++ } ++ } ++ } ++} ++ ++/* Fetch a videocore handle corresponding to a mapping of the pid+address ++** returns 0 (ie NULL) if no such handle exists in the global map. ++*/ ++static unsigned int vmcs_sm_vc_handle_from_pid_and_address(unsigned int pid, ++ unsigned int addr) ++{ ++ struct sm_mmap *map = NULL; ++ unsigned int handle = 0; ++ ++ if (!sm_state || addr == 0) ++ goto out; ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ /* Lookup the resource. ++ */ ++ if (!list_empty(&sm_state->map_list)) { ++ list_for_each_entry(map, &sm_state->map_list, map_list) { ++ if (map->res_pid != pid || map->res_addr != addr) ++ continue; ++ ++ pr_debug("[%s]: global map %p (pid %u, addr %lx) -> vc-hdl %x (usr-hdl %x)\n", ++ __func__, map, map->res_pid, map->res_addr, ++ map->res_vc_hdl, map->res_usr_hdl); ++ ++ handle = map->res_vc_hdl; ++ break; ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++out: ++ /* Use a debug log here as it may be a valid situation that we query ++ ** for something that is not mapped, we do not want a kernel log each ++ ** time around. ++ ** ++ ** There are other error log that would pop up accordingly if someone ++ ** subsequently tries to use something invalid after being told not to ++ ** use it... ++ */ ++ if (handle == 0) { ++ pr_debug("[%s]: not a valid map (pid %u, addr %x)\n", ++ __func__, pid, addr); ++ } ++ ++ return handle; ++} ++ ++/* Fetch a user handle corresponding to a mapping of the pid+address ++** returns 0 (ie NULL) if no such handle exists in the global map. ++*/ ++static unsigned int vmcs_sm_usr_handle_from_pid_and_address(unsigned int pid, ++ unsigned int addr) ++{ ++ struct sm_mmap *map = NULL; ++ unsigned int handle = 0; ++ ++ if (!sm_state || addr == 0) ++ goto out; ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ /* Lookup the resource. ++ */ ++ if (!list_empty(&sm_state->map_list)) { ++ list_for_each_entry(map, &sm_state->map_list, map_list) { ++ if (map->res_pid != pid || map->res_addr != addr) ++ continue; ++ ++ pr_debug("[%s]: global map %p (pid %u, addr %lx) -> usr-hdl %x (vc-hdl %x)\n", ++ __func__, map, map->res_pid, map->res_addr, ++ map->res_usr_hdl, map->res_vc_hdl); ++ ++ handle = map->res_usr_hdl; ++ break; ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++out: ++ /* Use a debug log here as it may be a valid situation that we query ++ * for something that is not mapped yet. ++ * ++ * There are other error log that would pop up accordingly if someone ++ * subsequently tries to use something invalid after being told not to ++ * use it... ++ */ ++ if (handle == 0) ++ pr_debug("[%s]: not a valid map (pid %u, addr %x)\n", ++ __func__, pid, addr); ++ ++ return handle; ++} ++ ++#if defined(DO_NOT_USE) ++/* Fetch an address corresponding to a mapping of the pid+handle ++** returns 0 (ie NULL) if no such address exists in the global map. ++*/ ++static unsigned int vmcs_sm_usr_address_from_pid_and_vc_handle(unsigned int pid, ++ unsigned int hdl) ++{ ++ struct sm_mmap *map = NULL; ++ unsigned int addr = 0; ++ ++ if (sm_state == NULL || hdl == 0) ++ goto out; ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ /* Lookup the resource. ++ */ ++ if (!list_empty(&sm_state->map_list)) { ++ list_for_each_entry(map, &sm_state->map_list, map_list) { ++ if (map->res_pid != pid || map->res_vc_hdl != hdl) ++ continue; ++ ++ pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n", ++ __func__, map, map->res_pid, map->res_vc_hdl, ++ map->res_usr_hdl, map->res_addr); ++ ++ addr = map->res_addr; ++ break; ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++out: ++ /* Use a debug log here as it may be a valid situation that we query ++ ** for something that is not mapped, we do not want a kernel log each ++ ** time around. ++ ** ++ ** There are other error log that would pop up accordingly if someone ++ ** subsequently tries to use something invalid after being told not to ++ ** use it... ++ */ ++ if (addr == 0) ++ pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n", ++ __func__, pid, hdl); ++ ++ return addr; ++} ++#endif ++ ++/* Fetch an address corresponding to a mapping of the pid+handle ++** returns 0 (ie NULL) if no such address exists in the global map. ++*/ ++static unsigned int vmcs_sm_usr_address_from_pid_and_usr_handle(unsigned int ++ pid, ++ unsigned int ++ hdl) ++{ ++ struct sm_mmap *map = NULL; ++ unsigned int addr = 0; ++ ++ if (sm_state == NULL || hdl == 0) ++ goto out; ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ /* Lookup the resource. ++ */ ++ if (!list_empty(&sm_state->map_list)) { ++ list_for_each_entry(map, &sm_state->map_list, map_list) { ++ if (map->res_pid != pid || map->res_usr_hdl != hdl) ++ continue; ++ ++ pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n", ++ __func__, map, map->res_pid, map->res_vc_hdl, ++ map->res_usr_hdl, map->res_addr); ++ ++ addr = map->res_addr; ++ break; ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++out: ++ /* Use a debug log here as it may be a valid situation that we query ++ * for something that is not mapped, we do not want a kernel log each ++ * time around. ++ * ++ * There are other error log that would pop up accordingly if someone ++ * subsequently tries to use something invalid after being told not to ++ * use it... ++ */ ++ if (addr == 0) ++ pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n", __func__, ++ pid, hdl); ++ ++ return addr; ++} ++ ++/* Adds a resource mapping to the global data list. ++*/ ++static void vmcs_sm_add_map(struct SM_STATE_T *state, ++ struct SM_RESOURCE_T *resource, struct sm_mmap *map) ++{ ++ mutex_lock(&(state->map_lock)); ++ ++ /* Add to the global list of mappings ++ */ ++ list_add(&map->map_list, &state->map_list); ++ ++ /* Add to the list of mappings for this resource ++ */ ++ list_add(&map->resource_map_list, &resource->map_list); ++ resource->map_count++; ++ ++ mutex_unlock(&(state->map_lock)); ++ ++ pr_debug("[%s]: added map %p (pid %u, vc-hdl %x, usr-hdl %x, addr %lx)\n", ++ __func__, map, map->res_pid, map->res_vc_hdl, ++ map->res_usr_hdl, map->res_addr); ++} ++ ++/* Removes a resource mapping from the global data list. ++*/ ++static void vmcs_sm_remove_map(struct SM_STATE_T *state, ++ struct SM_RESOURCE_T *resource, ++ struct sm_mmap *map) ++{ ++ mutex_lock(&(state->map_lock)); ++ ++ /* Remove from the global list of mappings ++ */ ++ list_del(&map->map_list); ++ ++ /* Remove from the list of mapping for this resource ++ */ ++ list_del(&map->resource_map_list); ++ if (resource->map_count > 0) ++ resource->map_count--; ++ ++ mutex_unlock(&(state->map_lock)); ++ ++ pr_debug("[%s]: removed map %p (pid %d, vc-hdl %x, usr-hdl %x, addr %lx)\n", ++ __func__, map, map->res_pid, map->res_vc_hdl, map->res_usr_hdl, ++ map->res_addr); ++ ++ kfree(map); ++} ++ ++/* Read callback for the global state proc entry. ++*/ ++static int vc_sm_global_state_show(struct seq_file *s, void *v) ++{ ++ struct sm_mmap *map = NULL; ++ int map_count = 0; ++ ++ if (sm_state == NULL) ++ return 0; ++ ++ seq_printf(s, "\nVC-ServiceHandle 0x%x\n", ++ (unsigned int)sm_state->sm_handle); ++ ++ /* Log all applicable mapping(s). ++ */ ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ if (!list_empty(&sm_state->map_list)) { ++ list_for_each_entry(map, &sm_state->map_list, map_list) { ++ map_count++; ++ ++ seq_printf(s, "\nMapping 0x%x\n", ++ (unsigned int)map); ++ seq_printf(s, " TGID %u\n", ++ map->res_pid); ++ seq_printf(s, " VC-HDL 0x%x\n", ++ map->res_vc_hdl); ++ seq_printf(s, " USR-HDL 0x%x\n", ++ map->res_usr_hdl); ++ seq_printf(s, " USR-ADDR 0x%lx\n", ++ map->res_addr); ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ seq_printf(s, "\n\nTotal map count: %d\n\n", map_count); ++ ++ return 0; ++} ++ ++static int vc_sm_global_statistics_show(struct seq_file *s, void *v) ++{ ++ int ix; ++ ++ /* Global state tracked statistics. ++ */ ++ if (sm_state != NULL) { ++ seq_puts(s, "\nDeceased Resources Statistics\n"); ++ ++ seq_printf(s, "\nNatural Cause (%u occurences)\n", ++ sm_state->res_deceased_cnt); ++ for (ix = 0; ix < END_ATTEMPT; ix++) { ++ if (sm_state->deceased[ix] > 0) { ++ seq_printf(s, " %u\t%s\n", ++ sm_state->deceased[ix], ++ sm_stats_human_read[ix]); ++ } ++ } ++ seq_puts(s, "\n"); ++ for (ix = 0; ix < END_ATTEMPT; ix++) { ++ if (sm_state->deceased[ix + END_ATTEMPT] > 0) { ++ seq_printf(s, " %u\tFAILED %s\n", ++ sm_state->deceased[ix + END_ATTEMPT], ++ sm_stats_human_read[ix]); ++ } ++ } ++ ++ seq_printf(s, "\nForcefull (%u occurences)\n", ++ sm_state->res_terminated_cnt); ++ for (ix = 0; ix < END_ATTEMPT; ix++) { ++ if (sm_state->terminated[ix] > 0) { ++ seq_printf(s, " %u\t%s\n", ++ sm_state->terminated[ix], ++ sm_stats_human_read[ix]); ++ } ++ } ++ seq_puts(s, "\n"); ++ for (ix = 0; ix < END_ATTEMPT; ix++) { ++ if (sm_state->terminated[ix + END_ATTEMPT] > 0) { ++ seq_printf(s, " %u\tFAILED %s\n", ++ sm_state->terminated[ix + ++ END_ATTEMPT], ++ sm_stats_human_read[ix]); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++#if 0 ++/* Read callback for the statistics proc entry. ++*/ ++static int vc_sm_statistics_show(struct seq_file *s, void *v) ++{ ++ int ix; ++ struct SM_PRIV_DATA_T *file_data; ++ struct SM_RESOURCE_T *resource; ++ int res_count = 0; ++ struct SM_PDE_T *p_pde; ++ ++ p_pde = (struct SM_PDE_T *)(s->private); ++ file_data = (struct SM_PRIV_DATA_T *)(p_pde->priv_data); ++ ++ if (file_data == NULL) ++ return 0; ++ ++ /* Per process statistics. ++ */ ++ ++ seq_printf(s, "\nStatistics for TGID %d\n", file_data->pid); ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ if (!list_empty(&file_data->resource_list)) { ++ list_for_each_entry(resource, &file_data->resource_list, ++ resource_list) { ++ res_count++; ++ ++ seq_printf(s, "\nGUID: 0x%x\n\n", ++ resource->res_guid); ++ for (ix = 0; ix < END_ATTEMPT; ix++) { ++ if (resource->res_stats[ix] > 0) { ++ seq_printf(s, ++ " %u\t%s\n", ++ resource->res_stats[ix], ++ sm_stats_human_read[ix]); ++ } ++ } ++ seq_puts(s, "\n"); ++ for (ix = 0; ix < END_ATTEMPT; ix++) { ++ if (resource->res_stats[ix + END_ATTEMPT] > 0) { ++ seq_printf(s, ++ " %u\tFAILED %s\n", ++ resource->res_stats[ ++ ix + END_ATTEMPT], ++ sm_stats_human_read[ix]); ++ } ++ } ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++ seq_printf(s, "\nResources Count %d\n", res_count); ++ ++ return 0; ++} ++#endif ++ ++#if 0 ++/* Read callback for the allocation proc entry. */ ++static int vc_sm_alloc_show(struct seq_file *s, void *v) ++{ ++ struct SM_PRIV_DATA_T *file_data; ++ struct SM_RESOURCE_T *resource; ++ int alloc_count = 0; ++ struct SM_PDE_T *p_pde; ++ ++ p_pde = (struct SM_PDE_T *)(s->private); ++ file_data = (struct SM_PRIV_DATA_T *)(p_pde->priv_data); ++ ++ if (!file_data) ++ return 0; ++ ++ /* Per process statistics. */ ++ seq_printf(s, "\nAllocation for TGID %d\n", file_data->pid); ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ if (!list_empty(&file_data->resource_list)) { ++ list_for_each_entry(resource, &file_data->resource_list, ++ resource_list) { ++ alloc_count++; ++ ++ seq_printf(s, "\nGUID: 0x%x\n", ++ resource->res_guid); ++ seq_printf(s, "Lock Count: %u\n", ++ resource->lock_count); ++ seq_printf(s, "Mapped: %s\n", ++ (resource->map_count ? "yes" : "no")); ++ seq_printf(s, "VC-handle: 0x%x\n", ++ resource->res_handle); ++ seq_printf(s, "VC-address: 0x%p\n", ++ resource->res_base_mem); ++ seq_printf(s, "VC-size (bytes): %u\n", ++ resource->res_size); ++ seq_printf(s, "Cache: %s\n", ++ sm_cache_map_vector[resource->res_cached]); ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++ seq_printf(s, "\n\nTotal allocation count: %d\n\n", alloc_count); ++ ++ return 0; ++} ++#endif ++ ++static int vc_sm_seq_file_show(struct seq_file *s, void *v) ++{ ++ struct SM_PDE_T *sm_pde; ++ ++ sm_pde = (struct SM_PDE_T *)(s->private); ++ ++ if (sm_pde && sm_pde->show) ++ sm_pde->show(s, v); ++ ++ return 0; ++} ++ ++static int vc_sm_single_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, vc_sm_seq_file_show, inode->i_private); ++} ++ ++static const struct file_operations vc_sm_debug_fs_fops = { ++ .open = vc_sm_single_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++/* Adds a resource to the private data list which tracks all the allocated ++** data. ++*/ ++static void vmcs_sm_add_resource(struct SM_PRIV_DATA_T *privdata, ++ struct SM_RESOURCE_T *resource) ++{ ++ mutex_lock(&(sm_state->map_lock)); ++ list_add(&resource->resource_list, &privdata->resource_list); ++ list_add(&resource->global_resource_list, &sm_state->resource_list); ++ mutex_unlock(&(sm_state->map_lock)); ++ ++ pr_debug("[%s]: added resource %p (base addr %p, hdl %x, size %u, cache %u)\n", ++ __func__, resource, resource->res_base_mem, ++ resource->res_handle, resource->res_size, resource->res_cached); ++} ++ ++/* Locates a resource and acquire a reference on it. ++** The resource won't be deleted while there is a reference on it. ++*/ ++static struct SM_RESOURCE_T *vmcs_sm_acquire_resource(struct SM_PRIV_DATA_T ++ *private, ++ unsigned int res_guid) ++{ ++ struct SM_RESOURCE_T *resource, *ret = NULL; ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ list_for_each_entry(resource, &private->resource_list, resource_list) { ++ if (resource->res_guid != res_guid) ++ continue; ++ ++ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n", ++ __func__, resource, resource->res_guid, ++ resource->res_base_mem, resource->res_handle, ++ resource->res_size, resource->res_cached); ++ resource->ref_count++; ++ ret = resource; ++ break; ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); + + return ret; +} + -+static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev) ++/* Locates a resource and acquire a reference on it. ++** The resource won't be deleted while there is a reference on it. ++*/ ++static struct SM_RESOURCE_T *vmcs_sm_acquire_first_resource( ++ struct SM_PRIV_DATA_T *private) +{ -+ return snd_soc_unregister_card(&snd_rpi_iqaudio_dac); ++ struct SM_RESOURCE_T *resource, *ret = NULL; ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ list_for_each_entry(resource, &private->resource_list, resource_list) { ++ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n", ++ __func__, resource, resource->res_guid, ++ resource->res_base_mem, resource->res_handle, ++ resource->res_size, resource->res_cached); ++ resource->ref_count++; ++ ret = resource; ++ break; ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++ return ret; +} + -+static const struct of_device_id iqaudio_of_match[] = { -+ { .compatible = "iqaudio,iqaudio-dac", }, -+ {}, ++/* Locates a resource and acquire a reference on it. ++** The resource won't be deleted while there is a reference on it. ++*/ ++static struct SM_RESOURCE_T *vmcs_sm_acquire_global_resource(unsigned int ++ res_guid) ++{ ++ struct SM_RESOURCE_T *resource, *ret = NULL; ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ list_for_each_entry(resource, &sm_state->resource_list, ++ global_resource_list) { ++ if (resource->res_guid != res_guid) ++ continue; ++ ++ pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n", ++ __func__, resource, resource->res_guid, ++ resource->res_base_mem, resource->res_handle, ++ resource->res_size, resource->res_cached); ++ resource->ref_count++; ++ ret = resource; ++ break; ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++ return ret; ++} ++ ++/* Release a previously acquired resource. ++** The resource will be deleted when its refcount reaches 0. ++*/ ++static void vmcs_sm_release_resource(struct SM_RESOURCE_T *resource, int force) ++{ ++ struct SM_PRIV_DATA_T *private = resource->private; ++ struct sm_mmap *map, *map_tmp; ++ struct SM_RESOURCE_T *res_tmp; ++ int ret; ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ if (--resource->ref_count) { ++ if (force) ++ pr_err("[%s]: resource %p in use\n", __func__, resource); ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ return; ++ } ++ ++ /* Time to free the resource. Start by removing it from the list */ ++ list_del(&resource->resource_list); ++ list_del(&resource->global_resource_list); ++ ++ /* Walk the global resource list, find out if the resource is used ++ * somewhere else. In which case we don't want to delete it. ++ */ ++ list_for_each_entry(res_tmp, &sm_state->resource_list, ++ global_resource_list) { ++ if (res_tmp->res_handle == resource->res_handle) { ++ resource->res_handle = 0; ++ break; ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++ pr_debug("[%s]: freeing data - guid %x, hdl %x, base address %p\n", ++ __func__, resource->res_guid, resource->res_handle, ++ resource->res_base_mem); ++ resource->res_stats[FREE]++; ++ ++ /* Make sure the resource we're removing is unmapped first */ ++ if (resource->map_count && !list_empty(&resource->map_list)) { ++ down_write(¤t->mm->mmap_sem); ++ list_for_each_entry_safe(map, map_tmp, &resource->map_list, ++ resource_map_list) { ++ ret = ++ do_munmap(current->mm, map->res_addr, ++ resource->res_size); ++ if (ret) { ++ pr_err("[%s]: could not unmap resource %p\n", ++ __func__, resource); ++ } ++ } ++ up_write(¤t->mm->mmap_sem); ++ } ++ ++ /* Free up the videocore allocated resource. ++ */ ++ if (resource->res_handle) { ++ VC_SM_FREE_T free = { ++ resource->res_handle, resource->res_base_mem ++ }; ++ int status = vc_vchi_sm_free(sm_state->sm_handle, &free, ++ &private->int_trans_id); ++ if (status != 0 && status != -EINTR) { ++ pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n", ++ __func__, status, private->int_trans_id); ++ resource->res_stats[FREE_FAIL]++; ++ ret = -EPERM; ++ } ++ } ++ ++ /* Free up the shared resource. ++ */ ++ if (resource->res_shared) ++ vmcs_sm_release_resource(resource->res_shared, 0); ++ ++ /* Free up the local resource tracking this allocation. ++ */ ++ vc_sm_resource_deceased(resource, force); ++ kfree(resource); ++} ++ ++/* Dump the map table for the driver. If process is -1, dumps the whole table, ++** if process is a valid pid (non -1) dump only the entries associated with the ++** pid of interest. ++*/ ++static void vmcs_sm_host_walk_map_per_pid(int pid) ++{ ++ struct sm_mmap *map = NULL; ++ ++ /* Make sure the device was started properly. ++ */ ++ if (sm_state == NULL) { ++ pr_err("[%s]: invalid device\n", __func__); ++ return; ++ } ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ /* Log all applicable mapping(s). ++ */ ++ if (!list_empty(&sm_state->map_list)) { ++ list_for_each_entry(map, &sm_state->map_list, map_list) { ++ if (pid == -1 || map->res_pid == pid) { ++ pr_info("[%s]: tgid: %u - vc-hdl: %x, usr-hdl: %x, usr-addr: %lx\n", ++ __func__, map->res_pid, map->res_vc_hdl, ++ map->res_usr_hdl, map->res_addr); ++ } ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++ return; ++} ++ ++/* Dump the allocation table from host side point of view. This only dumps the ++** data allocated for this process/device referenced by the file_data. ++*/ ++static void vmcs_sm_host_walk_alloc(struct SM_PRIV_DATA_T *file_data) ++{ ++ struct SM_RESOURCE_T *resource = NULL; ++ ++ /* Make sure the device was started properly. ++ */ ++ if ((sm_state == NULL) || (file_data == NULL)) { ++ pr_err("[%s]: invalid device\n", __func__); ++ return; ++ } ++ ++ mutex_lock(&(sm_state->map_lock)); ++ ++ if (!list_empty(&file_data->resource_list)) { ++ list_for_each_entry(resource, &file_data->resource_list, ++ resource_list) { ++ pr_info("[%s]: guid: %x - hdl: %x, vc-mem: %p, size: %u, cache: %u\n", ++ __func__, resource->res_guid, resource->res_handle, ++ resource->res_base_mem, resource->res_size, ++ resource->res_cached); ++ } ++ } ++ ++ mutex_unlock(&(sm_state->map_lock)); ++ ++ return; ++} ++ ++/* Create support for private data tracking. ++*/ ++static struct SM_PRIV_DATA_T *vc_sm_create_priv_data(pid_t id) ++{ ++ char alloc_name[32]; ++ struct SM_PRIV_DATA_T *file_data = NULL; ++ ++ /* Allocate private structure. */ ++ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL); ++ ++ if (!file_data) { ++ pr_err("[%s]: cannot allocate file data\n", __func__); ++ goto out; ++ } ++ ++ snprintf(alloc_name, sizeof(alloc_name), "%d", id); ++ ++ INIT_LIST_HEAD(&file_data->resource_list); ++ file_data->pid = id; ++ file_data->dir_pid = debugfs_create_dir(alloc_name, ++ sm_state->dir_alloc); ++#if 0 ++ /* TODO: fix this to support querying statistics per pid */ ++ ++ if (IS_ERR_OR_NULL(file_data->dir_pid)) { ++ file_data->dir_pid = NULL; ++ } else { ++ struct dentry *dir_entry; ++ ++ dir_entry = debugfs_create_file(VC_SM_RESOURCES, S_IRUGO, ++ file_data->dir_pid, file_data, ++ vc_sm_debug_fs_fops); ++ ++ file_data->dir_res.dir_entry = dir_entry; ++ file_data->dir_res.priv_data = file_data; ++ file_data->dir_res.show = &vc_sm_alloc_show; ++ ++ dir_entry = debugfs_create_file(VC_SM_STATS, S_IRUGO, ++ file_data->dir_pid, file_data, ++ vc_sm_debug_fs_fops); ++ ++ file_data->dir_res.dir_entry = dir_entry; ++ file_data->dir_res.priv_data = file_data; ++ file_data->dir_res.show = &vc_sm_statistics_show; ++ } ++ pr_debug("[%s]: private data allocated %p\n", __func__, file_data); ++ ++#endif ++out: ++ return file_data; ++} ++ ++/* Open the device. Creates a private state to help track all allocation ++** associated with this device. ++*/ ++static int vc_sm_open(struct inode *inode, struct file *file) ++{ ++ int ret = 0; ++ ++ /* Make sure the device was started properly. ++ */ ++ if (!sm_state) { ++ pr_err("[%s]: invalid device\n", __func__); ++ ret = -EPERM; ++ goto out; ++ } ++ ++ file->private_data = vc_sm_create_priv_data(current->tgid); ++ if (file->private_data == NULL) { ++ pr_err("[%s]: failed to create data tracker\n", __func__); ++ ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++/* Close the device. Free up all resources still associated with this device ++** at the time. ++*/ ++static int vc_sm_release(struct inode *inode, struct file *file) ++{ ++ struct SM_PRIV_DATA_T *file_data = ++ (struct SM_PRIV_DATA_T *)file->private_data; ++ struct SM_RESOURCE_T *resource; ++ int ret = 0; ++ ++ /* Make sure the device was started properly. ++ */ ++ if (sm_state == NULL || file_data == NULL) { ++ pr_err("[%s]: invalid device\n", __func__); ++ ret = -EPERM; ++ goto out; ++ } ++ ++ pr_debug("[%s]: using private data %p\n", __func__, file_data); ++ ++ if (file_data->restart_sys == -EINTR) { ++ VC_SM_ACTION_CLEAN_T action_clean; ++ ++ pr_debug("[%s]: releasing following EINTR on %u (trans_id: %u) (likely due to signal)...\n", ++ __func__, file_data->int_action, ++ file_data->int_trans_id); ++ ++ action_clean.res_action = file_data->int_action; ++ action_clean.action_trans_id = file_data->int_trans_id; ++ ++ vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean); ++ } ++ ++ while ((resource = vmcs_sm_acquire_first_resource(file_data)) != NULL) { ++ vmcs_sm_release_resource(resource, 0); ++ vmcs_sm_release_resource(resource, 1); ++ } ++ ++ /* Remove the corresponding proc entry. */ ++ debugfs_remove_recursive(file_data->dir_pid); ++ ++ /* Terminate the private data. ++ */ ++ kfree(file_data); ++ ++out: ++ return ret; ++} ++ ++static void vcsm_vma_open(struct vm_area_struct *vma) ++{ ++ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data; ++ ++ pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n", ++ __func__, vma->vm_start, vma->vm_end, (int)current->tgid, ++ (int)vma->vm_pgoff); ++ ++ map->ref_count++; ++} ++ ++static void vcsm_vma_close(struct vm_area_struct *vma) ++{ ++ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data; ++ ++ pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n", ++ __func__, vma->vm_start, vma->vm_end, (int)current->tgid, ++ (int)vma->vm_pgoff); ++ ++ map->ref_count--; ++ ++ /* Remove from the map table. ++ */ ++ if (map->ref_count == 0) ++ vmcs_sm_remove_map(sm_state, map->resource, map); ++} ++ ++static int vcsm_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data; ++ struct SM_RESOURCE_T *resource = map->resource; ++ pgoff_t page_offset; ++ unsigned long pfn; ++ int ret = 0; ++ ++ /* Lock the resource if necessary. ++ */ ++ if (!resource->lock_count) { ++ VC_SM_LOCK_UNLOCK_T lock_unlock; ++ VC_SM_LOCK_RESULT_T lock_result; ++ int status; ++ ++ lock_unlock.res_handle = resource->res_handle; ++ lock_unlock.res_mem = resource->res_base_mem; ++ ++ pr_debug("[%s]: attempt to lock data - hdl %x, base address %p\n", ++ __func__, lock_unlock.res_handle, lock_unlock.res_mem); ++ ++ /* Lock the videocore allocated resource. ++ */ ++ status = vc_vchi_sm_lock(sm_state->sm_handle, ++ &lock_unlock, &lock_result, 0); ++ if ((status != 0) || ++ ((status == 0) && (lock_result.res_mem == NULL))) { ++ pr_err("[%s]: failed to lock memory on videocore (status: %u)\n", ++ __func__, status); ++ resource->res_stats[LOCK_FAIL]++; ++ return VM_FAULT_SIGBUS; ++ } ++ ++ pfn = vcaddr_to_pfn((unsigned long)resource->res_base_mem); ++ outer_inv_range(__pfn_to_phys(pfn), ++ __pfn_to_phys(pfn) + resource->res_size); ++ ++ resource->res_stats[LOCK]++; ++ resource->lock_count++; ++ ++ /* Keep track of the new base memory. ++ */ ++ if ((lock_result.res_mem != NULL) && ++ (lock_result.res_old_mem != NULL) && ++ (lock_result.res_mem != lock_result.res_old_mem)) { ++ resource->res_base_mem = lock_result.res_mem; ++ } ++ } ++ ++ /* We don't use vmf->pgoff since that has the fake offset */ ++ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start); ++ pfn = (uint32_t)resource->res_base_mem & 0x3FFFFFFF; ++ pfn += mm_vc_mem_phys_addr; ++ pfn += page_offset; ++ pfn >>= PAGE_SHIFT; ++ ++ /* Finally, remap it */ ++ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); ++ ++ switch (ret) { ++ case 0: ++ case -ERESTARTSYS: ++ return VM_FAULT_NOPAGE; ++ case -ENOMEM: ++ case -EAGAIN: ++ return VM_FAULT_OOM; ++ default: ++ return VM_FAULT_SIGBUS; ++ } ++} ++ ++static struct vm_operations_struct vcsm_vm_ops = { ++ .open = vcsm_vma_open, ++ .close = vcsm_vma_close, ++ .fault = vcsm_vma_fault, +}; + -+static struct platform_driver snd_rpi_iqaudio_dac_driver = { -+ .driver = { -+ .name = "snd-rpi-iqaudio-dac", -+ .owner = THIS_MODULE, -+ .of_match_table = iqaudio_of_match, -+ }, -+ .probe = snd_rpi_iqaudio_dac_probe, -+ .remove = snd_rpi_iqaudio_dac_remove, ++/* Walks a VMA and clean each valid page from the cache */ ++static void vcsm_vma_cache_clean_page_range(unsigned long addr, ++ unsigned long end) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long pgd_next, pud_next, pmd_next; ++ ++ if (addr >= end) ++ return; ++ ++ /* Walk PGD */ ++ pgd = pgd_offset(current->mm, addr); ++ do { ++ pgd_next = pgd_addr_end(addr, end); ++ ++ if (pgd_none(*pgd) || pgd_bad(*pgd)) ++ continue; ++ ++ /* Walk PUD */ ++ pud = pud_offset(pgd, addr); ++ do { ++ pud_next = pud_addr_end(addr, pgd_next); ++ if (pud_none(*pud) || pud_bad(*pud)) ++ continue; ++ ++ /* Walk PMD */ ++ pmd = pmd_offset(pud, addr); ++ do { ++ pmd_next = pmd_addr_end(addr, pud_next); ++ if (pmd_none(*pmd) || pmd_bad(*pmd)) ++ continue; ++ ++ /* Walk PTE */ ++ pte = pte_offset_map(pmd, addr); ++ do { ++ if (pte_none(*pte) ++ || !pte_present(*pte)) ++ continue; ++ ++ /* Clean + invalidate */ ++ dmac_flush_range((const void *) addr, ++ (const void *) ++ (addr + PAGE_SIZE)); ++ ++ } while (pte++, addr += ++ PAGE_SIZE, addr != pmd_next); ++ pte_unmap(pte); ++ ++ } while (pmd++, addr = pmd_next, addr != pud_next); ++ ++ } while (pud++, addr = pud_next, addr != pgd_next); ++ } while (pgd++, addr = pgd_next, addr != end); ++} ++ ++/* Map an allocated data into something that the user space. ++*/ ++static int vc_sm_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int ret = 0; ++ struct SM_PRIV_DATA_T *file_data = ++ (struct SM_PRIV_DATA_T *)file->private_data; ++ struct SM_RESOURCE_T *resource = NULL; ++ struct sm_mmap *map = NULL; ++ ++ /* Make sure the device was started properly. ++ */ ++ if ((sm_state == NULL) || (file_data == NULL)) { ++ pr_err("[%s]: invalid device\n", __func__); ++ return -EPERM; ++ } ++ ++ pr_debug("[%s]: private data %p, guid %x\n", __func__, file_data, ++ ((unsigned int)vma->vm_pgoff << PAGE_SHIFT)); ++ ++ /* We lookup to make sure that the data we are being asked to mmap is ++ ** something that we allocated. ++ ** ++ ** We use the offset information as the key to tell us which resource ++ ** we are mapping. ++ */ ++ resource = vmcs_sm_acquire_resource(file_data, ++ ((unsigned int)vma->vm_pgoff << ++ PAGE_SHIFT)); ++ if (resource == NULL) { ++ pr_err("[%s]: failed to locate resource for guid %x\n", __func__, ++ ((unsigned int)vma->vm_pgoff << PAGE_SHIFT)); ++ return -ENOMEM; ++ } ++ ++ pr_debug("[%s]: guid %x, tgid %u, %u, %u\n", ++ __func__, resource->res_guid, current->tgid, resource->pid, ++ file_data->pid); ++ ++ /* Check permissions. ++ */ ++ if (resource->pid && (resource->pid != current->tgid)) { ++ pr_err("[%s]: current tgid %u != %u owner\n", ++ __func__, current->tgid, resource->pid); ++ ret = -EPERM; ++ goto error; ++ } ++ ++ /* Verify that what we are asked to mmap is proper. ++ */ ++ if (resource->res_size != (unsigned int)(vma->vm_end - vma->vm_start)) { ++ pr_err("[%s]: size inconsistency (resource: %u - mmap: %u)\n", ++ __func__, ++ resource->res_size, ++ (unsigned int)(vma->vm_end - vma->vm_start)); ++ ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ /* Keep track of the tuple in the global resource list such that one ++ * can do a mapping lookup for address/memory handle. ++ */ ++ map = kzalloc(sizeof(*map), GFP_KERNEL); ++ if (map == NULL) { ++ pr_err("[%s]: failed to allocate global tracking resource\n", ++ __func__); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ map->res_pid = current->tgid; ++ map->res_vc_hdl = resource->res_handle; ++ map->res_usr_hdl = resource->res_guid; ++ map->res_addr = (long unsigned int)vma->vm_start; ++ map->resource = resource; ++ map->vma = vma; ++ vmcs_sm_add_map(sm_state, resource, map); ++ ++ /* We are not actually mapping the pages, we just provide a fault ++ ** handler to allow pages to be mapped when accessed ++ */ ++ vma->vm_flags |= ++ VM_IO | VM_PFNMAP | VM_DONTCOPY | VM_DONTEXPAND; ++ vma->vm_ops = &vcsm_vm_ops; ++ vma->vm_private_data = map; ++ ++ /* vm_pgoff is the first PFN of the mapped memory */ ++ vma->vm_pgoff = (unsigned long)resource->res_base_mem & 0x3FFFFFFF; ++ vma->vm_pgoff += mm_vc_mem_phys_addr; ++ vma->vm_pgoff >>= PAGE_SHIFT; ++ ++ if ((resource->res_cached == VMCS_SM_CACHE_NONE) || ++ (resource->res_cached == VMCS_SM_CACHE_VC)) { ++ /* Allocated non host cached memory, honour it. ++ */ ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ } ++ ++ pr_debug("[%s]: resource %p (guid %x) - cnt %u, base address %p, handle %x, size %u (%u), cache %u\n", ++ __func__, ++ resource, resource->res_guid, resource->lock_count, ++ resource->res_base_mem, resource->res_handle, ++ resource->res_size, (unsigned int)(vma->vm_end - vma->vm_start), ++ resource->res_cached); ++ ++ pr_debug("[%s]: resource %p (base address %p, handle %x) - map-count %d, usr-addr %x\n", ++ __func__, resource, resource->res_base_mem, ++ resource->res_handle, resource->map_count, ++ (unsigned int)vma->vm_start); ++ ++ vcsm_vma_open(vma); ++ resource->res_stats[MAP]++; ++ vmcs_sm_release_resource(resource, 0); ++ return 0; ++ ++error: ++ vmcs_sm_release_resource(resource, 0); ++ resource->res_stats[MAP_FAIL]++; ++ return ret; ++} ++ ++/* Allocate a shared memory handle and block. ++*/ ++int vc_sm_ioctl_alloc(struct SM_PRIV_DATA_T *private, ++ struct vmcs_sm_ioctl_alloc *ioparam) ++{ ++ int ret = 0; ++ int status; ++ struct SM_RESOURCE_T *resource; ++ VC_SM_ALLOC_T alloc = { 0 }; ++ VC_SM_ALLOC_RESULT_T result = { 0 }; ++ ++ /* Setup our allocation parameters */ ++ alloc.type = ((ioparam->cached == VMCS_SM_CACHE_VC) ++ || (ioparam->cached == ++ VMCS_SM_CACHE_BOTH)) ? VC_SM_ALLOC_CACHED : ++ VC_SM_ALLOC_NON_CACHED; ++ alloc.base_unit = ioparam->size; ++ alloc.num_unit = ioparam->num; ++ alloc.allocator = current->tgid; ++ /* Align to kernel page size */ ++ alloc.alignement = 4096; ++ /* Align the size to the kernel page size */ ++ alloc.base_unit = ++ (alloc.base_unit + alloc.alignement - 1) & ~(alloc.alignement - 1); ++ if (*ioparam->name) { ++ memcpy(alloc.name, ioparam->name, sizeof(alloc.name) - 1); ++ } else { ++ memcpy(alloc.name, VMCS_SM_RESOURCE_NAME_DEFAULT, ++ sizeof(VMCS_SM_RESOURCE_NAME_DEFAULT)); ++ } ++ ++ pr_debug("[%s]: attempt to allocate \"%s\" data - type %u, base %u (%u), num %u, alignement %u\n", ++ __func__, alloc.name, alloc.type, ioparam->size, ++ alloc.base_unit, alloc.num_unit, alloc.alignement); ++ ++ /* Allocate local resource to track this allocation. ++ */ ++ resource = kzalloc(sizeof(*resource), GFP_KERNEL); ++ if (!resource) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ INIT_LIST_HEAD(&resource->map_list); ++ resource->ref_count++; ++ resource->pid = current->tgid; ++ ++ /* Allocate the videocore resource. ++ */ ++ status = vc_vchi_sm_alloc(sm_state->sm_handle, &alloc, &result, ++ &private->int_trans_id); ++ if (status == -EINTR) { ++ pr_debug("[%s]: requesting allocate memory action restart (trans_id: %u)\n", ++ __func__, private->int_trans_id); ++ ret = -ERESTARTSYS; ++ private->restart_sys = -EINTR; ++ private->int_action = VC_SM_MSG_TYPE_ALLOC; ++ goto error; ++ } else if (status != 0 || (status == 0 && result.res_mem == NULL)) { ++ pr_err("[%s]: failed to allocate memory on videocore (status: %u, trans_id: %u)\n", ++ __func__, status, private->int_trans_id); ++ ret = -ENOMEM; ++ resource->res_stats[ALLOC_FAIL]++; ++ goto error; ++ } ++ ++ /* Keep track of the resource we created. ++ */ ++ resource->private = private; ++ resource->res_handle = result.res_handle; ++ resource->res_base_mem = result.res_mem; ++ resource->res_size = alloc.base_unit * alloc.num_unit; ++ resource->res_cached = ioparam->cached; ++ ++ /* Kernel/user GUID. This global identifier is used for mmap'ing the ++ * allocated region from user space, it is passed as the mmap'ing ++ * offset, we use it to 'hide' the videocore handle/address. ++ */ ++ mutex_lock(&sm_state->lock); ++ resource->res_guid = ++sm_state->guid; ++ mutex_unlock(&sm_state->lock); ++ resource->res_guid <<= PAGE_SHIFT; ++ ++ vmcs_sm_add_resource(private, resource); ++ ++ pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n", ++ __func__, resource->res_guid, resource->res_handle, ++ resource->res_base_mem, resource->res_size, ++ resource->res_cached); ++ ++ /* We're done */ ++ resource->res_stats[ALLOC]++; ++ ioparam->handle = resource->res_guid; ++ return 0; ++ ++error: ++ pr_err("[%s]: failed to allocate \"%s\" data (%i) - type %u, base %u (%u), num %u, alignment %u\n", ++ __func__, alloc.name, ret, alloc.type, ioparam->size, ++ alloc.base_unit, alloc.num_unit, alloc.alignement); ++ if (resource != NULL) { ++ vc_sm_resource_deceased(resource, 1); ++ kfree(resource); ++ } ++ return ret; ++} ++ ++/* Share an allocate memory handle and block. ++*/ ++int vc_sm_ioctl_alloc_share(struct SM_PRIV_DATA_T *private, ++ struct vmcs_sm_ioctl_alloc_share *ioparam) ++{ ++ struct SM_RESOURCE_T *resource, *shared_resource; ++ int ret = 0; ++ ++ pr_debug("[%s]: attempt to share resource %u\n", __func__, ++ ioparam->handle); ++ ++ shared_resource = vmcs_sm_acquire_global_resource(ioparam->handle); ++ if (shared_resource == NULL) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ /* Allocate local resource to track this allocation. ++ */ ++ resource = kzalloc(sizeof(*resource), GFP_KERNEL); ++ if (resource == NULL) { ++ pr_err("[%s]: failed to allocate local tracking resource\n", ++ __func__); ++ ret = -ENOMEM; ++ goto error; ++ } ++ INIT_LIST_HEAD(&resource->map_list); ++ resource->ref_count++; ++ resource->pid = current->tgid; ++ ++ /* Keep track of the resource we created. ++ */ ++ resource->private = private; ++ resource->res_handle = shared_resource->res_handle; ++ resource->res_base_mem = shared_resource->res_base_mem; ++ resource->res_size = shared_resource->res_size; ++ resource->res_cached = shared_resource->res_cached; ++ resource->res_shared = shared_resource; ++ ++ mutex_lock(&sm_state->lock); ++ resource->res_guid = ++sm_state->guid; ++ mutex_unlock(&sm_state->lock); ++ resource->res_guid <<= PAGE_SHIFT; ++ ++ vmcs_sm_add_resource(private, resource); ++ ++ pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n", ++ __func__, resource->res_guid, resource->res_handle, ++ resource->res_base_mem, resource->res_size, ++ resource->res_cached); ++ ++ /* We're done */ ++ resource->res_stats[ALLOC]++; ++ ioparam->handle = resource->res_guid; ++ ioparam->size = resource->res_size; ++ return 0; ++ ++error: ++ pr_err("[%s]: failed to share %u\n", __func__, ioparam->handle); ++ if (shared_resource != NULL) ++ vmcs_sm_release_resource(shared_resource, 0); ++ ++ return ret; ++} ++ ++/* Free a previously allocated shared memory handle and block. ++*/ ++static int vc_sm_ioctl_free(struct SM_PRIV_DATA_T *private, ++ struct vmcs_sm_ioctl_free *ioparam) ++{ ++ struct SM_RESOURCE_T *resource = ++ vmcs_sm_acquire_resource(private, ioparam->handle); ++ ++ if (resource == NULL) { ++ pr_err("[%s]: resource for guid %u does not exist\n", __func__, ++ ioparam->handle); ++ return -EINVAL; ++ } ++ ++ /* Check permissions. ++ */ ++ if (resource->pid && (resource->pid != current->tgid)) { ++ pr_err("[%s]: current tgid %u != %u owner\n", ++ __func__, current->tgid, resource->pid); ++ vmcs_sm_release_resource(resource, 0); ++ return -EPERM; ++ } ++ ++ vmcs_sm_release_resource(resource, 0); ++ vmcs_sm_release_resource(resource, 0); ++ return 0; ++} ++ ++/* Resize a previously allocated shared memory handle and block. ++*/ ++static int vc_sm_ioctl_resize(struct SM_PRIV_DATA_T *private, ++ struct vmcs_sm_ioctl_resize *ioparam) ++{ ++ int ret = 0; ++ int status; ++ VC_SM_RESIZE_T resize; ++ struct SM_RESOURCE_T *resource; ++ ++ /* Locate resource from GUID. ++ */ ++ resource = vmcs_sm_acquire_resource(private, ioparam->handle); ++ if (!resource) { ++ pr_err("[%s]: failed resource - guid %x\n", ++ __func__, ioparam->handle); ++ ret = -EFAULT; ++ goto error; ++ } ++ ++ /* If the resource is locked, its reference count will be not NULL, ++ ** in which case we will not be allowed to resize it anyways, so ++ ** reject the attempt here. ++ */ ++ if (resource->lock_count != 0) { ++ pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n", ++ __func__, ioparam->handle, resource->lock_count); ++ ret = -EFAULT; ++ goto error; ++ } ++ ++ /* Check permissions. ++ */ ++ if (resource->pid && (resource->pid != current->tgid)) { ++ pr_err("[%s]: current tgid %u != %u owner\n", __func__, ++ current->tgid, resource->pid); ++ ret = -EPERM; ++ goto error; ++ } ++ ++ if (resource->map_count != 0) { ++ pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n", ++ __func__, ioparam->handle, resource->map_count); ++ ret = -EFAULT; ++ goto error; ++ } ++ ++ resize.res_handle = resource->res_handle; ++ resize.res_mem = resource->res_base_mem; ++ resize.res_new_size = ioparam->new_size; ++ ++ pr_debug("[%s]: attempt to resize data - guid %x, hdl %x, base address %p\n", ++ __func__, ioparam->handle, resize.res_handle, resize.res_mem); ++ ++ /* Resize the videocore allocated resource. ++ */ ++ status = vc_vchi_sm_resize(sm_state->sm_handle, &resize, ++ &private->int_trans_id); ++ if (status == -EINTR) { ++ pr_debug("[%s]: requesting resize memory action restart (trans_id: %u)\n", ++ __func__, private->int_trans_id); ++ ret = -ERESTARTSYS; ++ private->restart_sys = -EINTR; ++ private->int_action = VC_SM_MSG_TYPE_RESIZE; ++ goto error; ++ } else if (status != 0) { ++ pr_err("[%s]: failed to resize memory on videocore (status: %u, trans_id: %u)\n", ++ __func__, status, private->int_trans_id); ++ ret = -EPERM; ++ goto error; ++ } ++ ++ pr_debug("[%s]: success to resize data - hdl %x, size %d -> %d\n", ++ __func__, resize.res_handle, resource->res_size, ++ resize.res_new_size); ++ ++ /* Successfully resized, save the information and inform the user. ++ */ ++ ioparam->old_size = resource->res_size; ++ resource->res_size = resize.res_new_size; ++ ++error: ++ if (resource) ++ vmcs_sm_release_resource(resource, 0); ++ ++ return ret; ++} ++ ++/* Lock a previously allocated shared memory handle and block. ++*/ ++static int vc_sm_ioctl_lock(struct SM_PRIV_DATA_T *private, ++ struct vmcs_sm_ioctl_lock_unlock *ioparam, ++ int change_cache, enum vmcs_sm_cache_e cache_type, ++ unsigned int vc_addr) ++{ ++ int status; ++ VC_SM_LOCK_UNLOCK_T lock; ++ VC_SM_LOCK_RESULT_T result; ++ struct SM_RESOURCE_T *resource; ++ int ret = 0; ++ struct sm_mmap *map, *map_tmp; ++ long unsigned int phys_addr; ++ ++ map = NULL; ++ ++ /* Locate resource from GUID. ++ */ ++ resource = vmcs_sm_acquire_resource(private, ioparam->handle); ++ if (resource == NULL) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ /* Check permissions. ++ */ ++ if (resource->pid && (resource->pid != current->tgid)) { ++ pr_err("[%s]: current tgid %u != %u owner\n", __func__, ++ current->tgid, resource->pid); ++ ret = -EPERM; ++ goto error; ++ } ++ ++ lock.res_handle = resource->res_handle; ++ lock.res_mem = resource->res_base_mem; ++ ++ /* Take the lock and get the address to be mapped. ++ */ ++ if (vc_addr == 0) { ++ pr_debug("[%s]: attempt to lock data - guid %x, hdl %x, base address %p\n", ++ __func__, ioparam->handle, lock.res_handle, ++ lock.res_mem); ++ ++ /* Lock the videocore allocated resource. ++ */ ++ status = vc_vchi_sm_lock(sm_state->sm_handle, &lock, &result, ++ &private->int_trans_id); ++ if (status == -EINTR) { ++ pr_debug("[%s]: requesting lock memory action restart (trans_id: %u)\n", ++ __func__, private->int_trans_id); ++ ret = -ERESTARTSYS; ++ private->restart_sys = -EINTR; ++ private->int_action = VC_SM_MSG_TYPE_LOCK; ++ goto error; ++ } else if (status != 0 || ++ (status == 0 && result.res_mem == NULL)) { ++ pr_err("[%s]: failed to lock memory on videocore (status: %u, trans_id: %u)\n", ++ __func__, status, private->int_trans_id); ++ ret = -EPERM; ++ resource->res_stats[LOCK_FAIL]++; ++ goto error; ++ } ++ ++ pr_debug("[%s]: succeed to lock data - hdl %x, base address %p (%p), ref-cnt %d\n", ++ __func__, lock.res_handle, result.res_mem, ++ lock.res_mem, resource->lock_count); ++ } ++ /* Lock assumed taken already, address to be mapped is known. ++ */ ++ else ++ resource->res_base_mem = (void *)vc_addr; ++ ++ resource->res_stats[LOCK]++; ++ resource->lock_count++; ++ ++ /* Keep track of the new base memory allocation if it has changed. ++ */ ++ if ((vc_addr == 0) && ++ (result.res_mem != NULL) && ++ (result.res_old_mem != NULL) && ++ (result.res_mem != result.res_old_mem)) { ++ resource->res_base_mem = result.res_mem; ++ ++ /* Kernel allocated resources. ++ */ ++ if (resource->pid == 0) { ++ if (!list_empty(&resource->map_list)) { ++ list_for_each_entry_safe(map, map_tmp, ++ &resource->map_list, ++ resource_map_list) { ++ if (map->res_addr) { ++ iounmap((void *)map->res_addr); ++ map->res_addr = 0; ++ ++ vmcs_sm_remove_map(sm_state, ++ map->resource, ++ map); ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ if (change_cache) ++ resource->res_cached = cache_type; ++ ++ if (resource->map_count) { ++ ioparam->addr = ++ vmcs_sm_usr_address_from_pid_and_usr_handle( ++ current->tgid, ioparam->handle); ++ ++ pr_debug("[%s] map_count %d private->pid %d current->tgid %d hnd %x addr %u\n", ++ __func__, resource->map_count, private->pid, ++ current->tgid, ioparam->handle, ioparam->addr); ++ } else { ++ /* Kernel allocated resources. ++ */ ++ if (resource->pid == 0) { ++ pr_debug("[%s]: attempt mapping kernel resource - guid %x, hdl %x\n", ++ __func__, ioparam->handle, lock.res_handle); ++ ++ ioparam->addr = 0; ++ ++ map = kzalloc(sizeof(*map), GFP_KERNEL); ++ if (map == NULL) { ++ pr_err("[%s]: failed allocating tracker\n", ++ __func__); ++ ret = -ENOMEM; ++ goto error; ++ } else { ++ phys_addr = (uint32_t)resource->res_base_mem & ++ 0x3FFFFFFF; ++ phys_addr += mm_vc_mem_phys_addr; ++ if (resource->res_cached ++ == VMCS_SM_CACHE_HOST) { ++ ioparam->addr = (long unsigned int) ++ /* TODO - make cached work */ ++ ioremap_nocache(phys_addr, ++ resource->res_size); ++ ++ pr_debug("[%s]: mapping kernel - guid %x, hdl %x - cached mapping %u\n", ++ __func__, ioparam->handle, ++ lock.res_handle, ioparam->addr); ++ } else { ++ ioparam->addr = (long unsigned int) ++ ioremap_nocache(phys_addr, ++ resource->res_size); ++ ++ pr_debug("[%s]: mapping kernel- guid %x, hdl %x - non cached mapping %u\n", ++ __func__, ioparam->handle, ++ lock.res_handle, ioparam->addr); ++ } ++ ++ map->res_pid = 0; ++ map->res_vc_hdl = resource->res_handle; ++ map->res_usr_hdl = resource->res_guid; ++ map->res_addr = ioparam->addr; ++ map->resource = resource; ++ map->vma = NULL; ++ ++ vmcs_sm_add_map(sm_state, resource, map); ++ } ++ } else ++ ioparam->addr = 0; ++ } ++ ++error: ++ if (resource) ++ vmcs_sm_release_resource(resource, 0); ++ ++ return ret; ++} ++ ++/* Unlock a previously allocated shared memory handle and block. ++*/ ++static int vc_sm_ioctl_unlock(struct SM_PRIV_DATA_T *private, ++ struct vmcs_sm_ioctl_lock_unlock *ioparam, ++ int flush, int wait_reply, int no_vc_unlock) ++{ ++ int status; ++ VC_SM_LOCK_UNLOCK_T unlock; ++ struct sm_mmap *map, *map_tmp; ++ struct SM_RESOURCE_T *resource; ++ int ret = 0; ++ ++ map = NULL; ++ ++ /* Locate resource from GUID. ++ */ ++ resource = vmcs_sm_acquire_resource(private, ioparam->handle); ++ if (resource == NULL) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ /* Check permissions. ++ */ ++ if (resource->pid && (resource->pid != current->tgid)) { ++ pr_err("[%s]: current tgid %u != %u owner\n", ++ __func__, current->tgid, resource->pid); ++ ret = -EPERM; ++ goto error; ++ } ++ ++ unlock.res_handle = resource->res_handle; ++ unlock.res_mem = resource->res_base_mem; ++ ++ pr_debug("[%s]: attempt to unlock data - guid %x, hdl %x, base address %p\n", ++ __func__, ioparam->handle, unlock.res_handle, unlock.res_mem); ++ ++ /* User space allocated resources. ++ */ ++ if (resource->pid) { ++ /* Flush if requested */ ++ if (resource->res_cached && flush) { ++ dma_addr_t phys_addr = 0; ++ resource->res_stats[FLUSH]++; ++ ++ phys_addr = ++ (dma_addr_t)((uint32_t)resource->res_base_mem & ++ 0x3FFFFFFF); ++ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr; ++ ++ /* L1 cache flush */ ++ down_read(¤t->mm->mmap_sem); ++ list_for_each_entry(map, &resource->map_list, ++ resource_map_list) { ++ if (map->vma) { ++ unsigned long start; ++ unsigned long end; ++ start = map->vma->vm_start; ++ end = map->vma->vm_end; ++ ++ vcsm_vma_cache_clean_page_range( ++ start, end); ++ } ++ } ++ up_read(¤t->mm->mmap_sem); ++ ++ /* L2 cache flush */ ++ outer_clean_range(phys_addr, ++ phys_addr + ++ (size_t) resource->res_size); ++ } ++ ++ /* We need to zap all the vmas associated with this resource */ ++ if (resource->lock_count == 1) { ++ down_read(¤t->mm->mmap_sem); ++ list_for_each_entry(map, &resource->map_list, ++ resource_map_list) { ++ if (map->vma) { ++ zap_vma_ptes(map->vma, ++ map->vma->vm_start, ++ map->vma->vm_end - ++ map->vma->vm_start); ++ } ++ } ++ up_read(¤t->mm->mmap_sem); ++ } ++ } ++ /* Kernel allocated resources. */ ++ else { ++ /* Global + Taken in this context */ ++ if (resource->ref_count == 2) { ++ if (!list_empty(&resource->map_list)) { ++ list_for_each_entry_safe(map, map_tmp, ++ &resource->map_list, ++ resource_map_list) { ++ if (map->res_addr) { ++ if (flush && ++ (resource->res_cached == ++ VMCS_SM_CACHE_HOST)) { ++ long unsigned int ++ phys_addr; ++ phys_addr = (uint32_t) ++ resource->res_base_mem & 0x3FFFFFFF; ++ phys_addr += ++ mm_vc_mem_phys_addr; ++ ++ /* L1 cache flush */ ++ dmac_flush_range((const ++ void ++ *) ++ map->res_addr, (const void *) ++ (map->res_addr + resource->res_size)); ++ ++ /* L2 cache flush */ ++ outer_clean_range ++ (phys_addr, ++ phys_addr + ++ (size_t) ++ resource->res_size); ++ } ++ ++ iounmap((void *)map->res_addr); ++ map->res_addr = 0; ++ ++ vmcs_sm_remove_map(sm_state, ++ map->resource, ++ map); ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ if (resource->lock_count) { ++ /* Bypass the videocore unlock. ++ */ ++ if (no_vc_unlock) ++ status = 0; ++ /* Unlock the videocore allocated resource. ++ */ ++ else { ++ status = ++ vc_vchi_sm_unlock(sm_state->sm_handle, &unlock, ++ &private->int_trans_id, ++ wait_reply); ++ if (status == -EINTR) { ++ pr_debug("[%s]: requesting unlock memory action restart (trans_id: %u)\n", ++ __func__, private->int_trans_id); ++ ++ ret = -ERESTARTSYS; ++ resource->res_stats[UNLOCK]--; ++ private->restart_sys = -EINTR; ++ private->int_action = VC_SM_MSG_TYPE_UNLOCK; ++ goto error; ++ } else if (status != 0) { ++ pr_err("[%s]: failed to unlock vc mem (status: %u, trans_id: %u)\n", ++ __func__, status, private->int_trans_id); ++ ++ ret = -EPERM; ++ resource->res_stats[UNLOCK_FAIL]++; ++ goto error; ++ } ++ } ++ ++ resource->res_stats[UNLOCK]++; ++ resource->lock_count--; ++ } ++ ++ pr_debug("[%s]: success to unlock data - hdl %x, base address %p, ref-cnt %d\n", ++ __func__, unlock.res_handle, unlock.res_mem, ++ resource->lock_count); ++ ++error: ++ if (resource) ++ vmcs_sm_release_resource(resource, 0); ++ ++ return ret; ++} ++ ++/* Handle control from host. */ ++static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ unsigned int cmdnr = _IOC_NR(cmd); ++ struct SM_PRIV_DATA_T *file_data = ++ (struct SM_PRIV_DATA_T *)file->private_data; ++ struct SM_RESOURCE_T *resource = NULL; ++ ++ /* Validate we can work with this device. */ ++ if ((sm_state == NULL) || (file_data == NULL)) { ++ pr_err("[%s]: invalid device\n", __func__); ++ ret = -EPERM; ++ goto out; ++ } ++ ++ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr, ++ current->tgid, file_data->pid); ++ ++ /* Action is a re-post of a previously interrupted action? */ ++ if (file_data->restart_sys == -EINTR) { ++ VC_SM_ACTION_CLEAN_T action_clean; ++ ++ pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n", ++ __func__, file_data->int_action, ++ file_data->int_trans_id); ++ ++ action_clean.res_action = file_data->int_action; ++ action_clean.action_trans_id = file_data->int_trans_id; ++ ++ vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean); ++ ++ file_data->restart_sys = 0; ++ } ++ ++ /* Now process the command. ++ */ ++ switch (cmdnr) { ++ /* New memory allocation. ++ */ ++ case VMCS_SM_CMD_ALLOC: ++ { ++ struct vmcs_sm_ioctl_alloc ioparam; ++ ++ /* Get the parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = vc_sm_ioctl_alloc(file_data, &ioparam); ++ if (!ret && ++ (copy_to_user((void *)arg, ++ &ioparam, sizeof(ioparam)) != 0)) { ++ struct vmcs_sm_ioctl_free freeparam = { ++ ioparam.handle ++ }; ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ vc_sm_ioctl_free(file_data, &freeparam); ++ ret = -EFAULT; ++ } ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* Share existing memory allocation. ++ */ ++ case VMCS_SM_CMD_ALLOC_SHARE: ++ { ++ struct vmcs_sm_ioctl_alloc_share ioparam; ++ ++ /* Get the parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = vc_sm_ioctl_alloc_share(file_data, &ioparam); ++ ++ /* Copy result back to user. ++ */ ++ if (!ret ++ && copy_to_user((void *)arg, &ioparam, ++ sizeof(ioparam)) != 0) { ++ struct vmcs_sm_ioctl_free freeparam = { ++ ioparam.handle ++ }; ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ vc_sm_ioctl_free(file_data, &freeparam); ++ ret = -EFAULT; ++ } ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* Lock (attempt to) *and* register a cache behavior change. ++ */ ++ case VMCS_SM_CMD_LOCK_CACHE: ++ { ++ struct vmcs_sm_ioctl_lock_cache ioparam; ++ struct vmcs_sm_ioctl_lock_unlock lock; ++ ++ /* Get parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ lock.handle = ioparam.handle; ++ ret = ++ vc_sm_ioctl_lock(file_data, &lock, 1, ++ ioparam.cached, 0); ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* Lock (attempt to) existing memory allocation. ++ */ ++ case VMCS_SM_CMD_LOCK: ++ { ++ struct vmcs_sm_ioctl_lock_unlock ioparam; ++ ++ /* Get parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = vc_sm_ioctl_lock(file_data, &ioparam, 0, 0, 0); ++ ++ /* Copy result back to user. ++ */ ++ if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam)) ++ != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ } ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* Unlock (attempt to) existing memory allocation. ++ */ ++ case VMCS_SM_CMD_UNLOCK: ++ { ++ struct vmcs_sm_ioctl_lock_unlock ioparam; ++ ++ /* Get parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = vc_sm_ioctl_unlock(file_data, &ioparam, 0, 1, 0); ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* Resize (attempt to) existing memory allocation. ++ */ ++ case VMCS_SM_CMD_RESIZE: ++ { ++ struct vmcs_sm_ioctl_resize ioparam; ++ ++ /* Get parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = vc_sm_ioctl_resize(file_data, &ioparam); ++ ++ /* Copy result back to user. ++ */ ++ if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam)) ++ != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ } ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* Terminate existing memory allocation. ++ */ ++ case VMCS_SM_CMD_FREE: ++ { ++ struct vmcs_sm_ioctl_free ioparam; ++ ++ /* Get parameter data. ++ */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = vc_sm_ioctl_free(file_data, &ioparam); ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* Walk allocation on videocore, information shows up in the ++ ** videocore log. ++ */ ++ case VMCS_SM_CMD_VC_WALK_ALLOC: ++ { ++ pr_debug("[%s]: invoking walk alloc\n", __func__); ++ ++ if (vc_vchi_sm_walk_alloc(sm_state->sm_handle) != 0) ++ pr_err("[%s]: failed to walk-alloc on videocore\n", ++ __func__); ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++/* Walk mapping table on host, information shows up in the ++ ** kernel log. ++ */ ++ case VMCS_SM_CMD_HOST_WALK_MAP: ++ { ++ /* Use pid of -1 to tell to walk the whole map. */ ++ vmcs_sm_host_walk_map_per_pid(-1); ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* Walk mapping table per process on host. */ ++ case VMCS_SM_CMD_HOST_WALK_PID_ALLOC: ++ { ++ struct vmcs_sm_ioctl_walk ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ vmcs_sm_host_walk_alloc(file_data); ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* Walk allocation per process on host. */ ++ case VMCS_SM_CMD_HOST_WALK_PID_MAP: ++ { ++ struct vmcs_sm_ioctl_walk ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ vmcs_sm_host_walk_map_per_pid(ioparam.pid); ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* Gets the size of the memory associated with a user handle. */ ++ case VMCS_SM_CMD_SIZE_USR_HANDLE: ++ { ++ struct vmcs_sm_ioctl_size ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* Locate resource from GUID. */ ++ resource = ++ vmcs_sm_acquire_resource(file_data, ioparam.handle); ++ if (resource != NULL) { ++ ioparam.size = resource->res_size; ++ vmcs_sm_release_resource(resource, 0); ++ } else { ++ ioparam.size = 0; ++ } ++ ++ if (copy_to_user((void *)arg, ++ &ioparam, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ } ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* Verify we are dealing with a valid resource. */ ++ case VMCS_SM_CMD_CHK_USR_HANDLE: ++ { ++ struct vmcs_sm_ioctl_chk ioparam; ++ ++ /* Get parameter data. ++ */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* Locate resource from GUID. */ ++ resource = ++ vmcs_sm_acquire_resource(file_data, ioparam.handle); ++ if (resource == NULL) ++ ret = -EINVAL; ++ /* If the resource is cacheable, return additional ++ * information that may be needed to flush the cache. ++ */ ++ else if ((resource->res_cached == VMCS_SM_CACHE_HOST) || ++ (resource->res_cached == VMCS_SM_CACHE_BOTH)) { ++ ioparam.addr = ++ vmcs_sm_usr_address_from_pid_and_usr_handle ++ (current->tgid, ioparam.handle); ++ ioparam.size = resource->res_size; ++ ioparam.cache = resource->res_cached; ++ } else { ++ ioparam.addr = 0; ++ ioparam.size = 0; ++ ioparam.cache = resource->res_cached; ++ } ++ ++ if (resource) ++ vmcs_sm_release_resource(resource, 0); ++ ++ if (copy_to_user((void *)arg, ++ &ioparam, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ } ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* ++ * Maps a user handle given the process and the virtual address. ++ */ ++ case VMCS_SM_CMD_MAPPED_USR_HANDLE: ++ { ++ struct vmcs_sm_ioctl_map ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ioparam.handle = ++ vmcs_sm_usr_handle_from_pid_and_address( ++ ioparam.pid, ioparam.addr); ++ ++ resource = ++ vmcs_sm_acquire_resource(file_data, ioparam.handle); ++ if ((resource != NULL) ++ && ((resource->res_cached == VMCS_SM_CACHE_HOST) ++ || (resource->res_cached == ++ VMCS_SM_CACHE_BOTH))) { ++ ioparam.size = resource->res_size; ++ } else { ++ ioparam.size = 0; ++ } ++ ++ if (resource) ++ vmcs_sm_release_resource(resource, 0); ++ ++ if (copy_to_user((void *)arg, ++ &ioparam, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ } ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* ++ * Maps a videocore handle given process and virtual address. ++ */ ++ case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR: ++ { ++ struct vmcs_sm_ioctl_map ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ioparam.handle = vmcs_sm_vc_handle_from_pid_and_address( ++ ioparam.pid, ioparam.addr); ++ ++ if (copy_to_user((void *)arg, ++ &ioparam, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ++ ret = -EFAULT; ++ } ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ /* Maps a videocore handle given process and user handle. */ ++ case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL: ++ { ++ struct vmcs_sm_ioctl_map ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* Locate resource from GUID. */ ++ resource = ++ vmcs_sm_acquire_resource(file_data, ioparam.handle); ++ if (resource != NULL) { ++ ioparam.handle = resource->res_handle; ++ vmcs_sm_release_resource(resource, 0); ++ } else { ++ ioparam.handle = 0; ++ } ++ ++ if (copy_to_user((void *)arg, ++ &ioparam, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ++ ret = -EFAULT; ++ } ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* ++ * Maps a videocore address given process and videocore handle. ++ */ ++ case VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL: ++ { ++ struct vmcs_sm_ioctl_map ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* Locate resource from GUID. */ ++ resource = ++ vmcs_sm_acquire_resource(file_data, ioparam.handle); ++ if (resource != NULL) { ++ ioparam.addr = ++ (unsigned int)resource->res_base_mem; ++ vmcs_sm_release_resource(resource, 0); ++ } else { ++ ioparam.addr = 0; ++ } ++ ++ if (copy_to_user((void *)arg, ++ &ioparam, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ } ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* Maps a user address given process and vc handle. ++ */ ++ case VMCS_SM_CMD_MAPPED_USR_ADDRESS: ++ { ++ struct vmcs_sm_ioctl_map ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* ++ * Return the address information from the mapping, ++ * 0 (ie NULL) if it cannot locate the actual mapping. ++ */ ++ ioparam.addr = ++ vmcs_sm_usr_address_from_pid_and_usr_handle ++ (ioparam.pid, ioparam.handle); ++ ++ if (copy_to_user((void *)arg, ++ &ioparam, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ } ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* Flush the cache for a given mapping. */ ++ case VMCS_SM_CMD_FLUSH: ++ { ++ struct vmcs_sm_ioctl_cache ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* Locate resource from GUID. */ ++ resource = ++ vmcs_sm_acquire_resource(file_data, ioparam.handle); ++ ++ if ((resource != NULL) && resource->res_cached) { ++ dma_addr_t phys_addr = 0; ++ ++ resource->res_stats[FLUSH]++; ++ ++ phys_addr = ++ (dma_addr_t)((uint32_t) ++ resource->res_base_mem & ++ 0x3FFFFFFF); ++ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr; ++ ++ /* L1 cache flush */ ++ down_read(¤t->mm->mmap_sem); ++ vcsm_vma_cache_clean_page_range((unsigned long) ++ ioparam.addr, ++ (unsigned long) ++ ioparam.addr + ++ ioparam.size); ++ up_read(¤t->mm->mmap_sem); ++ ++ /* L2 cache flush */ ++ outer_clean_range(phys_addr, ++ phys_addr + ++ (size_t) ioparam.size); ++ } else if (resource == NULL) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (resource) ++ vmcs_sm_release_resource(resource, 0); ++ ++ /* Done. */ ++ goto out; ++ } ++ break; ++ ++ /* Invalidate the cache for a given mapping. */ ++ case VMCS_SM_CMD_INVALID: ++ { ++ struct vmcs_sm_ioctl_cache ioparam; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, ++ (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* Locate resource from GUID. ++ */ ++ resource = ++ vmcs_sm_acquire_resource(file_data, ioparam.handle); ++ ++ if ((resource != NULL) && resource->res_cached) { ++ dma_addr_t phys_addr = 0; ++ ++ resource->res_stats[INVALID]++; ++ ++ phys_addr = ++ (dma_addr_t)((uint32_t) ++ resource->res_base_mem & ++ 0x3FFFFFFF); ++ phys_addr += (dma_addr_t)mm_vc_mem_phys_addr; ++ ++ /* L2 cache invalidate */ ++ outer_inv_range(phys_addr, ++ phys_addr + ++ (size_t) ioparam.size); ++ ++ /* L1 cache invalidate */ ++ down_read(¤t->mm->mmap_sem); ++ vcsm_vma_cache_clean_page_range((unsigned long) ++ ioparam.addr, ++ (unsigned long) ++ ioparam.addr + ++ ioparam.size); ++ up_read(¤t->mm->mmap_sem); ++ } else if (resource == NULL) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (resource) ++ vmcs_sm_release_resource(resource, 0); ++ ++ /* Done. ++ */ ++ goto out; ++ } ++ break; ++ ++ default: ++ { ++ ret = -EINVAL; ++ goto out; ++ } ++ break; ++ } ++ ++out: ++ return ret; ++} ++ ++/* Device operations that we managed in this driver. ++*/ ++static const struct file_operations vmcs_sm_ops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = vc_sm_ioctl, ++ .open = vc_sm_open, ++ .release = vc_sm_release, ++ .mmap = vc_sm_mmap, +}; + -+module_platform_driver(snd_rpi_iqaudio_dac_driver); ++/* Creation of device. ++*/ ++static int vc_sm_create_sharedmemory(void) ++{ ++ int ret; + -+MODULE_AUTHOR("Florian Meier "); -+MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); ++ if (sm_state == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ /* Create a device class for creating dev nodes. ++ */ ++ sm_state->sm_class = class_create(THIS_MODULE, "vc-sm"); ++ if (IS_ERR(sm_state->sm_class)) { ++ pr_err("[%s]: unable to create device class\n", __func__); ++ ret = PTR_ERR(sm_state->sm_class); ++ goto out; ++ } ++ ++ /* Create a character driver. ++ */ ++ ret = alloc_chrdev_region(&sm_state->sm_devid, ++ DEVICE_MINOR, 1, DEVICE_NAME); ++ if (ret != 0) { ++ pr_err("[%s]: unable to allocate device number\n", __func__); ++ goto out_dev_class_destroy; ++ } ++ ++ cdev_init(&sm_state->sm_cdev, &vmcs_sm_ops); ++ ret = cdev_add(&sm_state->sm_cdev, sm_state->sm_devid, 1); ++ if (ret != 0) { ++ pr_err("[%s]: unable to register device\n", __func__); ++ goto out_chrdev_unreg; ++ } ++ ++ /* Create a device node. ++ */ ++ sm_state->sm_dev = device_create(sm_state->sm_class, ++ NULL, ++ MKDEV(MAJOR(sm_state->sm_devid), ++ DEVICE_MINOR), NULL, ++ DEVICE_NAME); ++ if (IS_ERR(sm_state->sm_dev)) { ++ pr_err("[%s]: unable to create device node\n", __func__); ++ ret = PTR_ERR(sm_state->sm_dev); ++ goto out_chrdev_del; ++ } ++ ++ goto out; ++ ++out_chrdev_del: ++ cdev_del(&sm_state->sm_cdev); ++out_chrdev_unreg: ++ unregister_chrdev_region(sm_state->sm_devid, 1); ++out_dev_class_destroy: ++ class_destroy(sm_state->sm_class); ++ sm_state->sm_class = NULL; ++out: ++ return ret; ++} ++ ++/* Termination of the device. ++*/ ++static int vc_sm_remove_sharedmemory(void) ++{ ++ int ret; ++ ++ if (sm_state == NULL) { ++ /* Nothing to do. ++ */ ++ ret = 0; ++ goto out; ++ } ++ ++ /* Remove the sharedmemory character driver. ++ */ ++ cdev_del(&sm_state->sm_cdev); ++ ++ /* Unregister region. ++ */ ++ unregister_chrdev_region(sm_state->sm_devid, 1); ++ ++ ret = 0; ++ goto out; ++ ++out: ++ return ret; ++} ++ ++/* Videocore connected. */ ++static void vc_sm_connected_init(void) ++{ ++ int ret; ++ VCHI_INSTANCE_T vchi_instance; ++ VCHI_CONNECTION_T *vchi_connection = NULL; ++ ++ pr_info("[%s]: start\n", __func__); ++ ++ /* Allocate memory for the state structure. ++ */ ++ sm_state = kzalloc(sizeof(struct SM_STATE_T), GFP_KERNEL); ++ if (sm_state == NULL) { ++ pr_err("[%s]: failed to allocate memory\n", __func__); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ mutex_init(&sm_state->lock); ++ mutex_init(&sm_state->map_lock); ++ ++ /* Initialize and create a VCHI connection for the shared memory service ++ ** running on videocore. ++ */ ++ ret = vchi_initialise(&vchi_instance); ++ if (ret != 0) { ++ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n", ++ __func__, ret); ++ ++ ret = -EIO; ++ goto err_free_mem; ++ } ++ ++ ret = vchi_connect(NULL, 0, vchi_instance); ++ if (ret != 0) { ++ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n", ++ __func__, ret); ++ ++ ret = -EIO; ++ goto err_free_mem; ++ } ++ ++ /* Initialize an instance of the shared memory service. */ ++ sm_state->sm_handle = ++ vc_vchi_sm_init(vchi_instance, &vchi_connection, 1); ++ if (sm_state->sm_handle == NULL) { ++ pr_err("[%s]: failed to initialize shared memory service\n", ++ __func__); ++ ++ ret = -EPERM; ++ goto err_free_mem; ++ } ++ ++ /* Create a debug fs directory entry (root). */ ++ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL); ++ if (!sm_state->dir_root) { ++ pr_err("[%s]: failed to create \'%s\' directory entry\n", ++ __func__, VC_SM_DIR_ROOT_NAME); ++ ++ ret = -EPERM; ++ goto err_stop_sm_service; ++ } ++ ++ sm_state->dir_state.show = &vc_sm_global_state_show; ++ sm_state->dir_state.dir_entry = debugfs_create_file(VC_SM_STATE, ++ S_IRUGO, sm_state->dir_root, &sm_state->dir_state, ++ &vc_sm_debug_fs_fops); ++ ++ sm_state->dir_stats.show = &vc_sm_global_statistics_show; ++ sm_state->dir_stats.dir_entry = debugfs_create_file(VC_SM_STATS, ++ S_IRUGO, sm_state->dir_root, &sm_state->dir_stats, ++ &vc_sm_debug_fs_fops); ++ ++ /* Create the proc entry children. */ ++ sm_state->dir_alloc = debugfs_create_dir(VC_SM_DIR_ALLOC_NAME, ++ sm_state->dir_root); ++ ++ /* Create a shared memory device. */ ++ ret = vc_sm_create_sharedmemory(); ++ if (ret != 0) { ++ pr_err("[%s]: failed to create shared memory device\n", ++ __func__); ++ goto err_remove_debugfs; ++ } ++ ++ INIT_LIST_HEAD(&sm_state->map_list); ++ INIT_LIST_HEAD(&sm_state->resource_list); ++ ++ sm_state->data_knl = vc_sm_create_priv_data(0); ++ if (sm_state->data_knl == NULL) { ++ pr_err("[%s]: failed to create kernel private data tracker\n", ++ __func__); ++ goto err_remove_shared_memory; ++ } ++ ++ /* Done! ++ */ ++ sm_inited = 1; ++ goto out; ++ ++err_remove_shared_memory: ++ vc_sm_remove_sharedmemory(); ++err_remove_debugfs: ++ debugfs_remove_recursive(sm_state->dir_root); ++err_stop_sm_service: ++ vc_vchi_sm_stop(&sm_state->sm_handle); ++err_free_mem: ++ kfree(sm_state); ++out: ++ pr_info("[%s]: end - returning %d\n", __func__, ret); ++} ++ ++/* Driver loading. */ ++static int __init vc_sm_init(void) ++{ ++ pr_info("vc-sm: Videocore shared memory driver\n"); ++ vchiq_add_connected_callback(vc_sm_connected_init); ++ return 0; ++} ++ ++/* Driver unloading. */ ++static void __exit vc_sm_exit(void) ++{ ++ pr_debug("[%s]: start\n", __func__); ++ if (sm_inited) { ++ /* Remove shared memory device. ++ */ ++ vc_sm_remove_sharedmemory(); ++ ++ /* Remove all proc entries. ++ */ ++ debugfs_remove_recursive(sm_state->dir_root); ++ ++ /* Stop the videocore shared memory service. ++ */ ++ vc_vchi_sm_stop(&sm_state->sm_handle); ++ ++ /* Free the memory for the state structure. ++ */ ++ mutex_destroy(&(sm_state->map_lock)); ++ kfree(sm_state); ++ } ++ ++ pr_debug("[%s]: end\n", __func__); ++} ++ ++#if defined(__KERNEL__) ++/* Allocate a shared memory handle and block. */ ++int vc_sm_alloc(VC_SM_ALLOC_T *alloc, int *handle) ++{ ++ struct vmcs_sm_ioctl_alloc ioparam = { 0 }; ++ int ret; ++ struct SM_RESOURCE_T *resource; ++ ++ /* Validate we can work with this device. ++ */ ++ if (sm_state == NULL || alloc == NULL || handle == NULL) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return -EPERM; ++ } ++ ++ ioparam.size = alloc->base_unit; ++ ioparam.num = alloc->num_unit; ++ ioparam.cached = ++ alloc->type == VC_SM_ALLOC_CACHED ? VMCS_SM_CACHE_VC : 0; ++ ++ ret = vc_sm_ioctl_alloc(sm_state->data_knl, &ioparam); ++ ++ if (ret == 0) { ++ resource = ++ vmcs_sm_acquire_resource(sm_state->data_knl, ++ ioparam.handle); ++ if (resource) { ++ resource->pid = 0; ++ vmcs_sm_release_resource(resource, 0); ++ ++ /* Assign valid handle at this time. ++ */ ++ *handle = ioparam.handle; ++ } else { ++ ret = -ENOMEM; ++ } ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vc_sm_alloc); ++ ++/* Get an internal resource handle mapped from the external one. ++*/ ++int vc_sm_int_handle(int handle) ++{ ++ struct SM_RESOURCE_T *resource; ++ int ret = 0; ++ ++ /* Validate we can work with this device. ++ */ ++ if (sm_state == NULL || handle == 0) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return 0; ++ } ++ ++ /* Locate resource from GUID. ++ */ ++ resource = vmcs_sm_acquire_resource(sm_state->data_knl, handle); ++ if (resource) { ++ ret = resource->res_handle; ++ vmcs_sm_release_resource(resource, 0); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vc_sm_int_handle); ++ ++/* Free a previously allocated shared memory handle and block. ++*/ ++int vc_sm_free(int handle) ++{ ++ struct vmcs_sm_ioctl_free ioparam = { handle }; ++ ++ /* Validate we can work with this device. ++ */ ++ if (sm_state == NULL || handle == 0) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return -EPERM; ++ } ++ ++ return vc_sm_ioctl_free(sm_state->data_knl, &ioparam); ++} ++EXPORT_SYMBOL_GPL(vc_sm_free); ++ ++/* Lock a memory handle for use by kernel. ++*/ ++int vc_sm_lock(int handle, VC_SM_LOCK_CACHE_MODE_T mode, ++ long unsigned int *data) ++{ ++ struct vmcs_sm_ioctl_lock_unlock ioparam; ++ int ret; ++ ++ /* Validate we can work with this device. ++ */ ++ if (sm_state == NULL || handle == 0 || data == NULL) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return -EPERM; ++ } ++ ++ *data = 0; ++ ++ ioparam.handle = handle; ++ ret = vc_sm_ioctl_lock(sm_state->data_knl, ++ &ioparam, ++ 1, ++ ((mode == ++ VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST : ++ VMCS_SM_CACHE_NONE), 0); ++ ++ *data = ioparam.addr; ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vc_sm_lock); ++ ++/* Unlock a memory handle in use by kernel. ++*/ ++int vc_sm_unlock(int handle, int flush, int no_vc_unlock) ++{ ++ struct vmcs_sm_ioctl_lock_unlock ioparam; ++ ++ /* Validate we can work with this device. ++ */ ++ if (sm_state == NULL || handle == 0) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return -EPERM; ++ } ++ ++ ioparam.handle = handle; ++ return vc_sm_ioctl_unlock(sm_state->data_knl, ++ &ioparam, flush, 0, no_vc_unlock); ++} ++EXPORT_SYMBOL_GPL(vc_sm_unlock); ++ ++/* Map a shared memory region for use by kernel. ++*/ ++int vc_sm_map(int handle, unsigned int sm_addr, VC_SM_LOCK_CACHE_MODE_T mode, ++ long unsigned int *data) ++{ ++ struct vmcs_sm_ioctl_lock_unlock ioparam; ++ int ret; ++ ++ /* Validate we can work with this device. ++ */ ++ if (sm_state == NULL || handle == 0 || data == NULL || sm_addr == 0) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return -EPERM; ++ } ++ ++ *data = 0; ++ ++ ioparam.handle = handle; ++ ret = vc_sm_ioctl_lock(sm_state->data_knl, ++ &ioparam, ++ 1, ++ ((mode == ++ VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST : ++ VMCS_SM_CACHE_NONE), sm_addr); ++ ++ *data = ioparam.addr; ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vc_sm_map); ++#endif ++ ++late_initcall(vc_sm_init); ++module_exit(vc_sm_exit); ++ ++MODULE_AUTHOR("Broadcom"); ++MODULE_DESCRIPTION("VideoCore SharedMemory Driver"); +MODULE_LICENSE("GPL v2"); -- 2.0.3 -From 38d43a3c52731319ed078146de6acc000dfa1837 Mon Sep 17 00:00:00 2001 -From: Howard Mitchell -Date: Wed, 30 Jul 2014 21:43:37 +0100 -Subject: [PATCH 80/81] soc-core: Fix volsw_range funcs so - SOC_DOUBLE_R_RANGE_TLV works. +From 0720b9af1c2a0b0a4a167172cc04957176b53700 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 7 Aug 2014 02:03:50 +0100 +Subject: [PATCH 69/69] Revert "ARM: dma: Use dma_pfn_offset for dma address + translation" -This is so that the correct range of values as specified -with the SOC_DOUBLE_R_RANGE_TLV macro are sent to the -hardware for both the normal and invert cases. +This reverts commit 6ce0d20016925d031f1e24d64302e4c976d7cec6. --- - sound/soc/soc-core.c | 22 ++++++++++------------ - 1 file changed, 10 insertions(+), 12 deletions(-) + arch/arm/include/asm/dma-mapping.h | 18 +----------------- + 1 file changed, 1 insertion(+), 17 deletions(-) -diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index 051c006..4d8917b 100644 ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -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; -- uinfo->value.integer.min = 0; -- uinfo->value.integer.max = platform_max - min; -+ uinfo->value.integer.min = min; -+ uinfo->value.integer.max = platform_max; - - return 0; +diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h +index c45b61a..0af6bd0 100644 +--- a/arch/arm/include/asm/dma-mapping.h ++++ b/arch/arm/include/asm/dma-mapping.h +@@ -58,37 +58,21 @@ static inline int dma_set_mask(struct device *dev, u64 mask) + #ifndef __arch_pfn_to_dma + static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn) + { +- if (dev) +- pfn -= dev->dma_pfn_offset; + return (dma_addr_t)__pfn_to_bus(pfn); } -@@ -3056,9 +3056,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, - unsigned int val, val_mask; - int ret; -- val = ((ucontrol->value.integer.value[0] + min) & mask); - if (invert) -- val = max - val; -+ val = ((max - ucontrol->value.integer.value[0] + min) & mask); -+ else -+ val = (ucontrol->value.integer.value[0] & mask); - val_mask = mask << shift; - val = val << shift; + static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr) + { +- unsigned long pfn = __bus_to_pfn(addr); +- +- if (dev) +- pfn += dev->dma_pfn_offset; +- +- return pfn; ++ return __bus_to_pfn(addr); + } -@@ -3067,9 +3068,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, - return ret; + static inline void *dma_to_virt(struct device *dev, dma_addr_t addr) + { +- if (dev) { +- unsigned long pfn = dma_to_pfn(dev, addr); +- +- return phys_to_virt(__pfn_to_phys(pfn)); +- } +- + return (void *)__bus_to_virt((unsigned long)addr); + } - if (snd_soc_volsw_is_stereo(mc)) { -- val = ((ucontrol->value.integer.value[1] + min) & mask); - if (invert) -- val = max - val; -+ val = ((max - ucontrol->value.integer.value[1] + min) & mask); -+ else -+ val = (ucontrol->value.integer.value[1] & mask); - val_mask = mask << shift; - val = val << shift; + static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) + { +- if (dev) +- return pfn_to_dma(dev, virt_to_pfn(addr)); +- + return (dma_addr_t)__virt_to_bus((unsigned long)(addr)); + } -@@ -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] = -- max - ucontrol->value.integer.value[0]; -- ucontrol->value.integer.value[0] = -- ucontrol->value.integer.value[0] - min; -+ max - ucontrol->value.integer.value[0] + min; - - if (snd_soc_volsw_is_stereo(mc)) { - ucontrol->value.integer.value[1] = - (snd_soc_read(codec, rreg) >> shift) & mask; - if (invert) - ucontrol->value.integer.value[1] = -- max - ucontrol->value.integer.value[1]; -- ucontrol->value.integer.value[1] = -- ucontrol->value.integer.value[1] - min; -+ max - ucontrol->value.integer.value[1] + min; - } - - return 0; --- -2.0.3 - - -From 8f39c5cb44f74baabbd511a82c212e675f097ddd Mon Sep 17 00:00:00 2001 -From: Howard Mitchell -Date: Fri, 28 Mar 2014 16:40:31 +0000 -Subject: [PATCH 81/81] pcm512x: Use a range macro for Volume and rename to - PCM. - -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 4b4c0c7..ec7e034 100644 ---- a/sound/soc/codecs/pcm512x.c -+++ b/sound/soc/codecs/pcm512x.c -@@ -259,8 +259,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("PCM", PCM512x_DIGITAL_VOLUME_2, -+ PCM512x_DIGITAL_VOLUME_3, 0, 40, 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, -- 2.0.3