brcm2708: add linux 4.4 support
authorFelix Fietkau <nbd@openwrt.org>
Sun, 17 Jan 2016 10:42:23 +0000 (10:42 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 17 Jan 2016 10:42:23 +0000 (10:42 +0000)
- random-bcm2708 and spi-bcm2708 have been removed.
- sound-soc-bcm2708-i2s has been upstreamed as sound-soc-bcm2835-i2s.

Let's keep linux 4.1 for a while, since linux 4.4 appears to have some issues
with multicast traffic on RPi ethernet:
https://gist.github.com/Noltari/5b1cfdecce5ed4bc08fd

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
SVN-Revision: 48266

127 files changed:
target/linux/brcm2708/bcm2708/config-4.4 [new file with mode: 0644]
target/linux/brcm2708/bcm2709/config-4.4 [new file with mode: 0644]
target/linux/brcm2708/modules.mk
target/linux/brcm2708/patches-4.4/0001-smsx95xx-fix-crimes-against-truesize.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0002-smsc95xx-Disable-turbo-mode-by-default.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0003-vmstat-Workaround-for-issue-where-dirty-page-count-g.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0004-BCM2835_DT-Fix-I2S-register-map.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0005-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0006-irqchip-bcm2835-Add-FIQ-support.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0007-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0008-serial-8250-Don-t-crash-when-nr_uarts-is-0.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0009-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0010-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0011-pinctrl-bcm2835-Only-request-the-interrupts-listed-i.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0012-spi-bcm2835-Support-pin-groups-other-than-7-11.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0013-ARM-bcm2835-Set-Serial-number-and-Revision.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0014-bcm2835-i2s-get-base-address-for-DMA-from-devicetree.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0015-bcm2835-i2s-add-24bit-support-update-bclk_ratio-to-m.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0016-bcm2835-i2s-setup-clock-only-if-CPU-is-clock-master.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0017-bcm2835-i2s-Eliminate-debugfs-directory-error.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0018-bcm2835-i2s-Register-PCM-device.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0019-bcm2835-i2s-Enable-MMAP-support-via-a-DT-property.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0020-dmaengine-bcm2835-Add-slave-dma-support.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0021-dmaengine-bcm2835-set-residue_granularity-field.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0022-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0023-bcm2835-dma-Fix-dreq-not-set-for-slave-transfers.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0024-bcm2835-dma-Limit-cyclic-transfers-on-lite-channels-.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0025-bcm2835-Add-support-for-uart1.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0026-firmware-bcm2835-Add-missing-property-tags.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0027-Main-bcm2708-bcm2709-linux-port.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0028-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0029-Add-dwc_otg-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0030-bcm2708-framebuffer-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0031-dmaengine-Add-support-for-BCM2708.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0032-Add-blk_pos-parameter-to-mmc-multi_io_quirk-callback.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0033-MMC-added-alternative-MMC-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0034-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0035-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0036-bcm2708-alsa-sound-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0037-bcm2708-vchiq-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0038-vc_mem-Add-vc_mem-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0039-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0040-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0041-Add-SMI-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0042-Add-SMI-NAND-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0043-lirc-added-support-for-RaspberryPi-GPIO.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0044-Add-cpufreq-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0045-Added-hwmon-thermal-driver-for-reporting-core-temper.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0046-Add-Chris-Boot-s-i2c-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0047-char-broadcom-Add-vcio-module.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0048-firmware-bcm2835-Support-ARCH_BCM270x.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0049-bcm2835-add-v4l2-camera-device.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0050-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0051-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0052-BCM2708-Add-core-Device-Tree-support.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0053-bcm2835-Match-with-BCM2708-Device-Trees.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0054-fbdev-add-FBIOCOPYAREA-ioctl.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0058-Speed-up-console-framebuffer-imageblit-function.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0059-Allow-mac-address-to-be-set-in-smsc95xx.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0060-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0061-Added-Device-IDs-for-August-DVB-T-205.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0062-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-PCM5102A-codec.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-HifiBerry-DAC.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0065-ASoC-Add-support-for-Rpi-DAC.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0066-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0067-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0068-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0069-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0070-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0071-Added-support-for-HiFiBerry-DAC.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0072-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0073-Update-ds1307-driver-for-device-tree-support.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0074-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0075-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0076-Add-driver-for-rpi-proto.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0077-config-Add-default-configs.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0078-bcm2835-bcm2835_defconfig.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0079-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0080-Improve-__copy_to_user-and-__copy_from_user-performa.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0081-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0082-spidev-Add-spidev-compatible-string-to-silence-warni.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0083-scripts-dtc-Add-overlay-support.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0084-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0085-RaspiDAC3-support.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0086-tpa6130a2-Add-headphone-switch-control.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0087-irq-bcm2835-Fix-building-with-2708.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0088-rpi_display-add-backlight-driver-and-overlay.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0089-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0090-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0091-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0092-drm-vc4-Force-HDMI-to-connected.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-fixes.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0094-drm-vc4-bo-cache-locking-cleanup.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0095-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0096-drm-vc4-Drop-struct_mutex-around-CL-validation.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0097-drm-vc4-Drop-struct_mutex-around-CL-validation.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0098-drm-vc4-Add-support-for-more-display-plane-formats.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0099-drm-vc4-No-need-to-stop-the-stopped-threads.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0100-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0101-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0102-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0103-squash-fixups.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0104-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0105-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0106-dts-Added-overlay-for-gpio_ir_recv-driver.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0107-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0108-New-overlay-for-PiScreen2r.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0109-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0110-Add-support-for-the-HiFiBerry-DAC-Pro.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0111-BCM270X_DT-Add-at86rf233-overlay.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0112-mm-Remove-the-PFN-busy-warning.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0113-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0114-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0115-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0116-drm-Use-the-driver-s-gem_object_free-function-from-C.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0117-drm-vc4-Add-support-for-MSAA-rendering.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0118-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0119-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0120-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0121-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0122-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0123-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0124-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0125-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0126-SDIO-overlay-add-bus_width-parameter.patch [new file with mode: 0644]
target/linux/brcm2708/patches-4.4/0127-fixup-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch [new file with mode: 0644]

diff --git a/target/linux/brcm2708/bcm2708/config-4.4 b/target/linux/brcm2708/bcm2708/config-4.4
new file mode 100644 (file)
index 0000000..22b8995
--- /dev/null
@@ -0,0 +1,355 @@
+# CONFIG_AIO is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_BCM2708=y
+# CONFIG_ARCH_BCM2709 is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_ERRATA_411920=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_BCM2708_NOL2CACHE is not set
+CONFIG_BCM2708_VCHIQ=y
+CONFIG_BCM2708_VCMEM=y
+# CONFIG_BCM2835_DEVGPIOMEM is not set
+CONFIG_BCM2835_MBOX=y
+# CONFIG_BCM2835_SMI is not set
+CONFIG_BCM2835_WDT=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM_VC_CMA=y
+CONFIG_BCM_VC_SM=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_SD=y
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BUILD_BIN2C=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMA=y
+CONFIG_CMA_ALIGNMENT=8
+CONFIG_CMA_AREAS=7
+# CONFIG_CMA_DEBUG is not set
+# CONFIG_CMA_DEBUGFS is not set
+CONFIG_CMA_SIZE_MBYTES=16
+# CONFIG_CMA_SIZE_SEL_MAX is not set
+CONFIG_CMA_SIZE_SEL_MBYTES=y
+# CONFIG_CMA_SIZE_SEL_MIN is not set
+# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+CONFIG_COMMON_CLK=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_PABRT_V6=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_V6=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DEVTMPFS=y
+CONFIG_DMADEVICES=y
+# CONFIG_DMA_BCM2708 is not set
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_CMA=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_RPISENSE is not set
+CONFIG_FIQ=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIX_EARLYCON_MEM=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_SUPPORT=y
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FREEZER=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HW_CONSOLE=y
+CONFIG_HZ_FIXED=0
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_IOMMU_HELPER=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LIBFDT=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_MACH_BCM2708=y
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAILBOX=y
+# CONFIG_MAILBOX_TEST is not set
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BCM2835=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD is not set
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_MACH_IO_H=y
+CONFIG_NEED_MACH_MEMORY_H=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NLS=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_OABI_COMPAT=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_NET=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+# CONFIG_PCI_SYSCALL is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYS_OFFSET=0
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_BCM2835=y
+# CONFIG_PL330_DMA is not set
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_RATIONAL=y
+CONFIG_RAW_DRIVER=y
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_PROC_FS is not set
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_SQUASHFS is not set
+CONFIG_SRCU=y
+# CONFIG_STAGING is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_SUNXI_SRAM is not set
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_SWIOTLB=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_TEXTSEARCH is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_BCM2835=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_OF=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_UID16 is not set
+CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_DWCOTG=y
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_NET_DRIVERS=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_UAS=y
+CONFIG_USB_USBNET=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/brcm2708/bcm2709/config-4.4 b/target/linux/brcm2708/bcm2709/config-4.4
new file mode 100644 (file)
index 0000000..99603a0
--- /dev/null
@@ -0,0 +1,387 @@
+# CONFIG_AIO is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_APM_EMULATION is not set
+# CONFIG_ARCH_BCM2708 is not set
+CONFIG_ARCH_BCM2709=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+# CONFIG_ARM_LPAE is not set
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_VIRT_EXT=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BCM2708_NOL2CACHE=y
+CONFIG_BCM2708_VCHIQ=y
+CONFIG_BCM2708_VCMEM=y
+# CONFIG_BCM2835_DEVGPIOMEM is not set
+CONFIG_BCM2835_MBOX=y
+# CONFIG_BCM2835_SMI is not set
+CONFIG_BCM2835_WDT=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM_VC_CMA=y
+CONFIG_BCM_VC_SM=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_SD=y
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BUILD_BIN2C=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMA=y
+CONFIG_CMA_ALIGNMENT=8
+CONFIG_CMA_AREAS=7
+# CONFIG_CMA_DEBUG is not set
+# CONFIG_CMA_DEBUGFS is not set
+CONFIG_CMA_SIZE_MBYTES=16
+# CONFIG_CMA_SIZE_SEL_MAX is not set
+CONFIG_CMA_SIZE_SEL_MBYTES=y
+# CONFIG_CMA_SIZE_SEL_MIN is not set
+# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+CONFIG_COMMON_CLK=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DEVTMPFS=y
+CONFIG_DMADEVICES=y
+# CONFIG_DMA_BCM2708 is not set
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_CMA=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_RPISENSE is not set
+CONFIG_FIQ=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIX_EARLYCON_MEM=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_SUPPORT=y
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FREEZER=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HW_CONSOLE=y
+CONFIG_HZ_FIXED=0
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_IOMMU_HELPER=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LIBFDT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MACH_BCM2709=y
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAILBOX=y
+# CONFIG_MAILBOX_TEST is not set
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BCM2835=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD is not set
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_MACH_IO_H=y
+CONFIG_NEED_MACH_MEMORY_H=y
+CONFIG_NEON=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NLS=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_OABI_COMPAT=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_NET=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGE_OFFSET=0x80000000
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+# CONFIG_PCI_SYSCALL is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYS_OFFSET=0
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_BCM2835=y
+# CONFIG_PL330_DMA is not set
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_RATIONAL=y
+CONFIG_RAW_DRIVER=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_PROC_FS is not set
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_SQUASHFS is not set
+CONFIG_SRCU=y
+# CONFIG_STAGING is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_SUNXI_SRAM is not set
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_SWIOTLB=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_TEXTSEARCH is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_BCM2835=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_OF=y
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TREE_RCU=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_UID16 is not set
+CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_DWCOTG=y
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_NET_DRIVERS=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_UAS=y
+CONFIG_USB_USBNET=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_VMSPLIT_2G=y
+# CONFIG_VMSPLIT_3G is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZONE_DMA_FLAG=0
index 3bc592c..4a00152 100644 (file)
@@ -36,7 +36,7 @@ define KernelPackage/sound-soc-bcm2708-i2s
   FILES:= \
        $(LINUX_DIR)/sound/soc/bcm/snd-soc-bcm2708-i2s.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-bcm2708-i2s)
-  DEPENDS:=@TARGET_brcm2708 +kmod-regmap +kmod-sound-soc-core
+  DEPENDS:=@TARGET_brcm2708 @LINUX_4_1 +kmod-regmap +kmod-sound-soc-core
   $(call AddDepends/sound)
 endef
 
@@ -46,6 +46,25 @@ endef
 
 $(eval $(call KernelPackage,sound-soc-bcm2708-i2s))
 
+define KernelPackage/sound-soc-bcm2835-i2s
+  TITLE:=SoC Audio support for the Broadcom 2835 I2S module
+  KCONFIG:= \
+       CONFIG_SND_BCM2835_SOC_I2S \
+       CONFIG_SND_SOC_DMAENGINE_PCM=y \
+       CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
+  FILES:= \
+       $(LINUX_DIR)/sound/soc/bcm/snd-soc-bcm2835-i2s.ko
+  AUTOLOAD:=$(call AutoLoad,68,snd-soc-bcm2835-i2s)
+  DEPENDS:=@TARGET_brcm2708 @LINUX_4_4 +kmod-regmap +kmod-sound-soc-core
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-bcm2835-i2s/description
+  This package contains support for codecs attached to the Broadcom 2835 I2S interface
+endef
+
+$(eval $(call KernelPackage,sound-soc-bcm2835-i2s))
+
 define KernelPackage/sound-soc-hifiberry-dac
   TITLE:=Support for HifiBerry DAC
   KCONFIG:= \
@@ -55,7 +74,10 @@ define KernelPackage/sound-soc-hifiberry-dac
        $(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-dac.ko \
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm5102a.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm5102a snd-soc-hifiberry-dac)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+       LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+       LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+       +kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -75,7 +97,10 @@ define KernelPackage/sound-soc-hifiberry-dacplus
        $(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-dacplus.ko \
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko
   AUTOLOAD:=$(call AutoLoad,68,clk-hifiberry-dacpro snd-soc-pcm512x snd-soc-hifiberry-dacplus)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+       LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+       LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+       +kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -94,7 +119,10 @@ define KernelPackage/sound-soc-hifiberry-digi
        $(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-digi.ko \
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8804.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-wm8804 snd-soc-hifiberry-digi)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+       LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+       LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+       +kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -113,7 +141,10 @@ define KernelPackage/sound-soc-hifiberry-amp
        $(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-amp.ko \
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-tas5713.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-tas5713 snd-soc-hifiberry-amp)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+       LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+       LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+       +kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -132,7 +163,10 @@ define KernelPackage/sound-soc-rpi-dac
        $(LINUX_DIR)/sound/soc/bcm/snd-soc-rpi-dac.ko \
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm1794a.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm1794a snd-soc-rpi-dac)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+       LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+       LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+       +kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -151,7 +185,10 @@ define KernelPackage/sound-soc-rpi-proto
        $(LINUX_DIR)/sound/soc/bcm/snd-soc-rpi-proto.ko \
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8731.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-wm8731 snd-soc-rpi-proto)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+       LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+       LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+       +kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -172,7 +209,10 @@ define KernelPackage/sound-soc-iqaudio-dac
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko \
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x-i2c.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-pcm512x-i2c snd-soc-iqaudio-dac)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+       LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+       LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+       +kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -195,7 +235,10 @@ define KernelPackage/sound-soc-raspidac3
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x-i2c.ko \
        $(LINUX_DIR)/sound/soc/codecs/snd-soc-tpa6130a2.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-pcm512x-i2c snd-soc-tpa6130a2 snd-soc-raspidac3)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+       LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+       LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+       +kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -212,7 +255,7 @@ define KernelPackage/random-bcm2708
   KCONFIG:=CONFIG_HW_RANDOM_BCM2708
   FILES:=$(LINUX_DIR)/drivers/char/hw_random/bcm2708-rng.ko
   AUTOLOAD:=$(call AutoLoad,11,bcm2708-rng)
-  DEPENDS:=@TARGET_brcm2708 +kmod-random-core
+  DEPENDS:=@TARGET_brcm2708 @LINUX_4_1 +kmod-random-core
 endef
 
 define KernelPackage/random-bcm2708/description
@@ -281,7 +324,7 @@ define KernelPackage/spi-bcm2708
     CONFIG_SPI_MASTER=y
   FILES:=$(LINUX_DIR)/drivers/spi/spi-bcm2708.ko
   AUTOLOAD:=$(call AutoLoad,89,spi-bcm2708)
-  DEPENDS:=@TARGET_brcm2708
+  DEPENDS:=@TARGET_brcm2708 @LINUX_4_1
 endef
 
 define KernelPackage/spi-bcm2708/description
diff --git a/target/linux/brcm2708/patches-4.4/0001-smsx95xx-fix-crimes-against-truesize.patch b/target/linux/brcm2708/patches-4.4/0001-smsx95xx-fix-crimes-against-truesize.patch
new file mode 100644 (file)
index 0000000..48cb813
--- /dev/null
@@ -0,0 +1,33 @@
+From 8c2c0f30ef9ee0eccd3e56c6aeb110097569d5aa Mon Sep 17 00:00:00 2001
+From: Steve Glendinning <steve.glendinning@smsc.com>
+Date: Thu, 19 Feb 2015 18:47:12 +0000
+Subject: [PATCH 001/127] smsx95xx: fix crimes against truesize
+
+smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings.
+
+This patch stops smsc95xx from changing truesize.
+
+Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>
+---
+ drivers/net/usb/smsc95xx.c | 2 --
+ 1 file changed, 2 deletions(-)
+ mode change 100644 => 100755 drivers/net/usb/smsc95xx.c
+
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -1785,7 +1785,6 @@ static int smsc95xx_rx_fixup(struct usbn
+                               if (dev->net->features & NETIF_F_RXCSUM)
+                                       smsc95xx_rx_csum_offload(skb);
+                               skb_trim(skb, skb->len - 4); /* remove fcs */
+-                              skb->truesize = size + sizeof(struct sk_buff);
+                               return 1;
+                       }
+@@ -1803,7 +1802,6 @@ static int smsc95xx_rx_fixup(struct usbn
+                       if (dev->net->features & NETIF_F_RXCSUM)
+                               smsc95xx_rx_csum_offload(ax_skb);
+                       skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
+-                      ax_skb->truesize = size + sizeof(struct sk_buff);
+                       usbnet_skb_return(dev, ax_skb);
+               }
diff --git a/target/linux/brcm2708/patches-4.4/0002-smsc95xx-Disable-turbo-mode-by-default.patch b/target/linux/brcm2708/patches-4.4/0002-smsc95xx-Disable-turbo-mode-by-default.patch
new file mode 100644 (file)
index 0000000..185da76
--- /dev/null
@@ -0,0 +1,20 @@
+From 96f6fc6f990423f39b73013cd91f00a615315a90 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 17 Apr 2015 16:58:45 +0100
+Subject: [PATCH 002/127] smsc95xx: Disable turbo mode by default
+
+---
+ drivers/net/usb/smsc95xx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -70,7 +70,7 @@ struct smsc95xx_priv {
+       u8 suspend_flags;
+ };
+-static bool turbo_mode = true;
++static bool turbo_mode = false;
+ module_param(turbo_mode, bool, 0644);
+ MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
diff --git a/target/linux/brcm2708/patches-4.4/0003-vmstat-Workaround-for-issue-where-dirty-page-count-g.patch b/target/linux/brcm2708/patches-4.4/0003-vmstat-Workaround-for-issue-where-dirty-page-count-g.patch
new file mode 100644 (file)
index 0000000..4361b54
--- /dev/null
@@ -0,0 +1,27 @@
+From 3ea06ff9ba42a29f37b46ced2fb90ff9e06da445 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 18 Jun 2014 13:42:01 +0100
+Subject: [PATCH 003/127] vmstat: Workaround for issue where dirty page count
+ goes negative
+
+See:
+https://github.com/raspberrypi/linux/issues/617
+http://www.spinics.net/lists/linux-mm/msg72236.html
+---
+ include/linux/vmstat.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/include/linux/vmstat.h
++++ b/include/linux/vmstat.h
+@@ -219,7 +219,11 @@ static inline void __inc_zone_state(stru
+ static inline void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
+ {
+       atomic_long_dec(&zone->vm_stat[item]);
++      if (item == NR_FILE_DIRTY && unlikely(atomic_long_read(&zone->vm_stat[item]) < 0))
++              atomic_long_set(&zone->vm_stat[item], 0);
+       atomic_long_dec(&vm_stat[item]);
++      if (item == NR_FILE_DIRTY && unlikely(atomic_long_read(&vm_stat[item]) < 0))
++              atomic_long_set(&vm_stat[item], 0);
+ }
+ static inline void __inc_zone_page_state(struct page *page,
diff --git a/target/linux/brcm2708/patches-4.4/0004-BCM2835_DT-Fix-I2S-register-map.patch b/target/linux/brcm2708/patches-4.4/0004-BCM2835_DT-Fix-I2S-register-map.patch
new file mode 100644 (file)
index 0000000..1b4a086
--- /dev/null
@@ -0,0 +1,50 @@
+From 6c72a609c205138b739a1484aa1a4ce6dd395c43 Mon Sep 17 00:00:00 2001
+From: Robert Tiemann <rtie@gmx.de>
+Date: Mon, 20 Jul 2015 11:01:25 +0200
+Subject: [PATCH 004/127] BCM2835_DT: Fix I2S register map
+
+---
+ Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt   | 4 ++--
+ Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt | 4 ++--
+ arch/arm/boot/dts/bcm2835.dtsi                               | 4 ++--
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt
++++ b/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt
+@@ -48,8 +48,8 @@ Example:
+ bcm2835_i2s: i2s@7e203000 {
+       compatible = "brcm,bcm2835-i2s";
+-      reg = < 0x7e203000 0x20>,
+-            < 0x7e101098 0x02>;
++      reg = < 0x7e203000 0x24>,
++            < 0x7e101098 0x08>;
+       dmas = <&dma 2>,
+              <&dma 3>;
+--- a/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt
++++ b/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt
+@@ -16,8 +16,8 @@ Example:
+ bcm2835_i2s: i2s@7e203000 {
+       compatible = "brcm,bcm2835-i2s";
+-      reg = <0x7e203000 0x20>,
+-            <0x7e101098 0x02>;
++      reg = <0x7e203000 0x24>,
++            <0x7e101098 0x08>;
+       dmas = <&dma 2>,
+              <&dma 3>;
+--- a/arch/arm/boot/dts/bcm2835.dtsi
++++ b/arch/arm/boot/dts/bcm2835.dtsi
+@@ -120,8 +120,8 @@
+               i2s: i2s@7e203000 {
+                       compatible = "brcm,bcm2835-i2s";
+-                      reg = <0x7e203000 0x20>,
+-                            <0x7e101098 0x02>;
++                      reg = <0x7e203000 0x24>,
++                            <0x7e101098 0x08>;
+                       dmas = <&dma 2>,
+                              <&dma 3>;
diff --git a/target/linux/brcm2708/patches-4.4/0005-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch b/target/linux/brcm2708/patches-4.4/0005-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch
new file mode 100644 (file)
index 0000000..a0dc4e7
--- /dev/null
@@ -0,0 +1,31 @@
+From 38395f1ae1258743c3e0081c86bb4b65ad06dd69 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 4 Dec 2015 17:41:50 +0000
+Subject: [PATCH 005/127] irq-bcm2836: Prevent spurious interrupts, and trap
+ them early
+
+The old arch-specific IRQ macros included a dsb to ensure the
+write to clear the mailbox interrupt completed before returning
+from the interrupt. The BCM2836 irqchip driver needs the same
+precaution to avoid spurious interrupts.
+
+Spurious interrupts are still possible for other reasons,
+though, so trap them early.
+---
+ drivers/irqchip/irq-bcm2836.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/irqchip/irq-bcm2836.c
++++ b/drivers/irqchip/irq-bcm2836.c
+@@ -170,9 +170,10 @@ __exception_irq_entry bcm2836_arm_irqchi
+               u32 ipi = ffs(mbox_val) - 1;
+               writel(1 << ipi, mailbox0);
++              dsb();
+               handle_IPI(ipi, regs);
+ #endif
+-      } else {
++      } else if (stat) {
+               u32 hwirq = ffs(stat) - 1;
+               handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
diff --git a/target/linux/brcm2708/patches-4.4/0006-irqchip-bcm2835-Add-FIQ-support.patch b/target/linux/brcm2708/patches-4.4/0006-irqchip-bcm2835-Add-FIQ-support.patch
new file mode 100644 (file)
index 0000000..28ba48b
--- /dev/null
@@ -0,0 +1,127 @@
+From 44b5e890373665231d9a5876966ef3a670b9efd7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Fri, 12 Jun 2015 19:01:05 +0200
+Subject: [PATCH 006/127] irqchip: bcm2835: Add FIQ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add a duplicate irq range with an offset on the hwirq's so the
+driver can detect that enable_fiq() is used.
+Tested with downstream dwc_otg USB controller driver.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+---
+ arch/arm/mach-bcm/Kconfig     |  1 +
+ drivers/irqchip/irq-bcm2835.c | 51 ++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 47 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -128,6 +128,7 @@ config ARCH_BCM2835
+       select ARM_ERRATA_411920
+       select ARM_TIMER_SP804
+       select CLKSRC_OF
++      select FIQ
+       select PINCTRL
+       select PINCTRL_BCM2835
+       help
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -55,7 +55,7 @@
+ #include <asm/mach/irq.h>
+ /* Put the bank and irq (32 bits) into the hwirq */
+-#define MAKE_HWIRQ(b, n)      ((b << 5) | (n))
++#define MAKE_HWIRQ(b, n)      (((b) << 5) | (n))
+ #define HWIRQ_BANK(i)         (i >> 5)
+ #define HWIRQ_BIT(i)          BIT(i & 0x1f)
+@@ -71,9 +71,13 @@
+                                       | SHORTCUT1_MASK | SHORTCUT2_MASK)
+ #define REG_FIQ_CONTROL               0x0c
++#define REG_FIQ_ENABLE                0x80
++#define REG_FIQ_DISABLE               0
+ #define NR_BANKS              3
+ #define IRQS_PER_BANK         32
++#define NUMBER_IRQS           MAKE_HWIRQ(NR_BANKS, 0)
++#define FIQ_START             (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
+ static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
+ static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
+@@ -98,14 +102,38 @@ static void __exception_irq_entry bcm283
+       struct pt_regs *regs);
+ static void bcm2836_chained_handle_irq(struct irq_desc *desc);
++static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
++{
++      hwirq -= NUMBER_IRQS;
++      /*
++       * The hwirq numbering used in this driver is:
++       *   BASE (0-7) GPU1 (32-63) GPU2 (64-95).
++       * This differ from the one used in the FIQ register:
++       *   GPU1 (0-31) GPU2 (32-63) BASE (64-71)
++       */
++      if (hwirq >= 32)
++              return hwirq - 32;
++
++      return hwirq + 64;
++}
++
+ static void armctrl_mask_irq(struct irq_data *d)
+ {
+-      writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
++      if (d->hwirq >= NUMBER_IRQS)
++              writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
++      else
++              writel_relaxed(HWIRQ_BIT(d->hwirq),
++                             intc.disable[HWIRQ_BANK(d->hwirq)]);
+ }
+ static void armctrl_unmask_irq(struct irq_data *d)
+ {
+-      writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
++      if (d->hwirq >= NUMBER_IRQS)
++              writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
++                             intc.base + REG_FIQ_CONTROL);
++      else
++              writel_relaxed(HWIRQ_BIT(d->hwirq),
++                             intc.enable[HWIRQ_BANK(d->hwirq)]);
+ }
+ static struct irq_chip armctrl_chip = {
+@@ -151,8 +179,9 @@ static int __init armctrl_of_init(struct
+               panic("%s: unable to map IC registers\n",
+                       node->full_name);
+-      intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
+-                      &armctrl_ops, NULL);
++      intc.base = base;
++      intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2,
++                                          &armctrl_ops, NULL);
+       if (!intc.domain)
+               panic("%s: unable to create IRQ domain\n", node->full_name);
+@@ -182,6 +211,18 @@ static int __init armctrl_of_init(struct
+               set_handle_irq(bcm2835_handle_irq);
+       }
++      /* Make a duplicate irq range which is used to enable FIQ */
++      for (b = 0; b < NR_BANKS; b++) {
++              for (i = 0; i < bank_irqs[b]; i++) {
++                      irq = irq_create_mapping(intc.domain,
++                                      MAKE_HWIRQ(b, i) + NUMBER_IRQS);
++                      BUG_ON(irq <= 0);
++                      irq_set_chip(irq, &armctrl_chip);
++                      set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++              }
++      }
++      init_FIQ(FIQ_START);
++
+       return 0;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0007-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch b/target/linux/brcm2708/patches-4.4/0007-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch
new file mode 100644 (file)
index 0000000..9fa768c
--- /dev/null
@@ -0,0 +1,96 @@
+From e3e8c56abfe6a036025f75908b63ae69d8eaed11 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Fri, 23 Oct 2015 16:26:55 +0200
+Subject: [PATCH 007/127] irqchip: irq-bcm2835: Add 2836 FIQ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/irqchip/irq-bcm2835.c | 42 ++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 40 insertions(+), 2 deletions(-)
+
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -50,6 +50,8 @@
+ #include <linux/of_irq.h>
+ #include <linux/irqchip.h>
+ #include <linux/irqdomain.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
+ #include <asm/exception.h>
+ #include <asm/mach/irq.h>
+@@ -70,6 +72,9 @@
+ #define BANK0_VALID_MASK      (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
+                                       | SHORTCUT1_MASK | SHORTCUT2_MASK)
++#undef ARM_LOCAL_GPU_INT_ROUTING
++#define ARM_LOCAL_GPU_INT_ROUTING 0x0c
++
+ #define REG_FIQ_CONTROL               0x0c
+ #define REG_FIQ_ENABLE                0x80
+ #define REG_FIQ_DISABLE               0
+@@ -95,6 +100,7 @@ struct armctrl_ic {
+       void __iomem *enable[NR_BANKS];
+       void __iomem *disable[NR_BANKS];
+       struct irq_domain *domain;
++      struct regmap *local_regmap;
+ };
+ static struct armctrl_ic intc __read_mostly;
+@@ -128,12 +134,35 @@ static void armctrl_mask_irq(struct irq_
+ static void armctrl_unmask_irq(struct irq_data *d)
+ {
+-      if (d->hwirq >= NUMBER_IRQS)
++      if (d->hwirq >= NUMBER_IRQS) {
++              if (num_online_cpus() > 1) {
++                      unsigned int data;
++                      int ret;
++
++                      if (!intc.local_regmap) {
++                              pr_err("FIQ is disabled due to missing regmap\n");
++                              return;
++                      }
++
++                      ret = regmap_read(intc.local_regmap,
++                                        ARM_LOCAL_GPU_INT_ROUTING, &data);
++                      if (ret) {
++                              pr_err("Failed to read int routing %d\n", ret);
++                              return;
++                      }
++
++                      data &= ~0xc;
++                      data |= (1 << 2);
++                      regmap_write(intc.local_regmap,
++                                   ARM_LOCAL_GPU_INT_ROUTING, data);
++              }
++
+               writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
+                              intc.base + REG_FIQ_CONTROL);
+-      else
++      } else {
+               writel_relaxed(HWIRQ_BIT(d->hwirq),
+                              intc.enable[HWIRQ_BANK(d->hwirq)]);
++      }
+ }
+ static struct irq_chip armctrl_chip = {
+@@ -211,6 +240,15 @@ static int __init armctrl_of_init(struct
+               set_handle_irq(bcm2835_handle_irq);
+       }
++      if (is_2836) {
++              intc.local_regmap =
++                      syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
++              if (IS_ERR(intc.local_regmap)) {
++                      pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
++                      intc.local_regmap = NULL;
++              }
++      }
++
+       /* Make a duplicate irq range which is used to enable FIQ */
+       for (b = 0; b < NR_BANKS; b++) {
+               for (i = 0; i < bank_irqs[b]; i++) {
diff --git a/target/linux/brcm2708/patches-4.4/0008-serial-8250-Don-t-crash-when-nr_uarts-is-0.patch b/target/linux/brcm2708/patches-4.4/0008-serial-8250-Don-t-crash-when-nr_uarts-is-0.patch
new file mode 100644 (file)
index 0000000..46bc447
--- /dev/null
@@ -0,0 +1,20 @@
+From 4bff078f28e6a2d55d18e06c0a92b0b78b8ea6cb Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 30 Jun 2015 14:12:42 +0100
+Subject: [PATCH 008/127] serial: 8250: Don't crash when nr_uarts is 0
+
+---
+ drivers/tty/serial/8250/8250_core.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/tty/serial/8250/8250_core.c
++++ b/drivers/tty/serial/8250/8250_core.c
+@@ -509,6 +509,8 @@ static void __init serial8250_isa_init_p
+       if (nr_uarts > UART_NR)
+               nr_uarts = UART_NR;
++      if (!nr_uarts)
++              return;
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
diff --git a/target/linux/brcm2708/patches-4.4/0009-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch b/target/linux/brcm2708/patches-4.4/0009-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch
new file mode 100644 (file)
index 0000000..96381b6
--- /dev/null
@@ -0,0 +1,22 @@
+From 91ea61bbf9285586d27442dc3b85ea34805ccf38 Mon Sep 17 00:00:00 2001
+From: notro <notro@tronnes.org>
+Date: Thu, 10 Jul 2014 13:59:47 +0200
+Subject: [PATCH 009/127] pinctrl-bcm2835: Set base to 0 give expected gpio
+ numbering
+
+Signed-off-by: Noralf Tronnes <notro@tronnes.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -373,7 +373,7 @@ static struct gpio_chip bcm2835_gpio_chi
+       .get = bcm2835_gpio_get,
+       .set = bcm2835_gpio_set,
+       .to_irq = bcm2835_gpio_to_irq,
+-      .base = -1,
++      .base = 0,
+       .ngpio = BCM2835_NUM_GPIOS,
+       .can_sleep = false,
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0010-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch b/target/linux/brcm2708/patches-4.4/0010-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch
new file mode 100644 (file)
index 0000000..c3a051f
--- /dev/null
@@ -0,0 +1,146 @@
+From 15367f46e17775c4d736ed1cfc318218362c6a4d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 24 Feb 2015 13:40:50 +0000
+Subject: [PATCH 010/127] pinctrl-bcm2835: Fix interrupt handling for GPIOs
+ 28-31 and 46-53
+
+Contrary to the documentation, the BCM2835 GPIO controller actually has
+four interrupt lines - one each for the three IRQ groups and one common. Rather
+confusingly, the GPIO interrupt groups don't correspond directly with the GPIO
+control banks. Instead, GPIOs 0-27 generate IRQ GPIO0, 28-45 GPIO1 and
+46-53 GPIO2.
+
+Awkwardly, the GPIOS for IRQ GPIO1 straddle two 32-entry GPIO banks, so it is
+cleaner to split out a function to process the interrupts for a single GPIO
+bank.
+
+This bug has only just been observed because GPIOs above 27 can only be
+accessed on an old Raspberry Pi with the optional P5 header fitted, where
+the pins are often used for I2S instead.
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 51 ++++++++++++++++++++++++++---------
+ 1 file changed, 39 insertions(+), 12 deletions(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -47,6 +47,7 @@
+ #define MODULE_NAME "pinctrl-bcm2835"
+ #define BCM2835_NUM_GPIOS 54
+ #define BCM2835_NUM_BANKS 2
++#define BCM2835_NUM_IRQS  3
+ #define BCM2835_PIN_BITMAP_SZ \
+       DIV_ROUND_UP(BCM2835_NUM_GPIOS, sizeof(unsigned long) * 8)
+@@ -88,13 +89,13 @@ enum bcm2835_pinconf_pull {
+ struct bcm2835_gpio_irqdata {
+       struct bcm2835_pinctrl *pc;
+-      int bank;
++      int irqgroup;
+ };
+ struct bcm2835_pinctrl {
+       struct device *dev;
+       void __iomem *base;
+-      int irq[BCM2835_NUM_BANKS];
++      int irq[BCM2835_NUM_IRQS];
+       /* note: locking assumes each bank will have its own unsigned long */
+       unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
+@@ -105,7 +106,7 @@ struct bcm2835_pinctrl {
+       struct gpio_chip gpio_chip;
+       struct pinctrl_gpio_range gpio_range;
+-      struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_BANKS];
++      struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_IRQS];
+       spinlock_t irq_lock[BCM2835_NUM_BANKS];
+ };
+@@ -378,17 +379,16 @@ static struct gpio_chip bcm2835_gpio_chi
+       .can_sleep = false,
+ };
+-static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id)
++static int bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
++                                      unsigned int bank, u32 mask)
+ {
+-      struct bcm2835_gpio_irqdata *irqdata = dev_id;
+-      struct bcm2835_pinctrl *pc = irqdata->pc;
+-      int bank = irqdata->bank;
+       unsigned long events;
+       unsigned offset;
+       unsigned gpio;
+       unsigned int type;
+       events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4);
++      events &= mask;
+       events &= pc->enabled_irq_map[bank];
+       for_each_set_bit(offset, &events, 32) {
+               gpio = (32 * bank) + offset;
+@@ -396,7 +396,30 @@ static irqreturn_t bcm2835_gpio_irq_hand
+               generic_handle_irq(irq_linear_revmap(pc->irq_domain, gpio));
+       }
+-      return events ? IRQ_HANDLED : IRQ_NONE;
++
++      return (events != 0);
++}
++
++static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id)
++{
++      struct bcm2835_gpio_irqdata *irqdata = dev_id;
++      struct bcm2835_pinctrl *pc = irqdata->pc;
++      int handled = 0;
++
++      switch (irqdata->irqgroup) {
++      case 0: /* IRQ0 covers GPIOs 0-27 */
++              handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff);
++              break;
++      case 1: /* IRQ1 covers GPIOs 28-45 */
++              handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000) |
++                        bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff);
++              break;
++      case 2: /* IRQ2 covers GPIOs 46-53 */
++              handled = bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000);
++              break;
++      }
++
++      return handled ? IRQ_HANDLED : IRQ_NONE;
+ }
+ static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
+@@ -985,8 +1008,6 @@ static int bcm2835_pinctrl_probe(struct
+       for (i = 0; i < BCM2835_NUM_BANKS; i++) {
+               unsigned long events;
+               unsigned offset;
+-              int len;
+-              char *name;
+               /* clear event detection flags */
+               bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0);
+@@ -1001,10 +1022,15 @@ static int bcm2835_pinctrl_probe(struct
+               for_each_set_bit(offset, &events, 32)
+                       bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset));
++              spin_lock_init(&pc->irq_lock[i]);
++      }
++
++      for (i = 0; i < BCM2835_NUM_IRQS; i++) {
++              int len;
++              char *name;
+               pc->irq[i] = irq_of_parse_and_map(np, i);
+               pc->irq_data[i].pc = pc;
+-              pc->irq_data[i].bank = i;
+-              spin_lock_init(&pc->irq_lock[i]);
++              pc->irq_data[i].irqgroup = i;
+               len = strlen(dev_name(pc->dev)) + 16;
+               name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
+@@ -1062,6 +1088,7 @@ static struct platform_driver bcm2835_pi
+       .remove = bcm2835_pinctrl_remove,
+       .driver = {
+               .name = MODULE_NAME,
++              .owner = THIS_MODULE,
+               .of_match_table = bcm2835_pinctrl_match,
+       },
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0011-pinctrl-bcm2835-Only-request-the-interrupts-listed-i.patch b/target/linux/brcm2708/patches-4.4/0011-pinctrl-bcm2835-Only-request-the-interrupts-listed-i.patch
new file mode 100644 (file)
index 0000000..0ef4ba2
--- /dev/null
@@ -0,0 +1,27 @@
+From 167da31b9a7d3111c83993e4d614bb95bbefdcbb Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 26 Feb 2015 09:58:22 +0000
+Subject: [PATCH 011/127] pinctrl-bcm2835: Only request the interrupts listed
+ in the DTB
+
+Although the GPIO controller can generate three interrupts (four counting
+the common one), the device tree files currently only specify two. In the
+absence of the third, simply don't register that interrupt (as opposed to
+registering 0), which has the effect of making it impossible to generate
+interrupts for GPIOs 46-53 which, since they share pins with the SD card
+interface, is unlikely to be a problem.
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1029,6 +1029,8 @@ static int bcm2835_pinctrl_probe(struct
+               int len;
+               char *name;
+               pc->irq[i] = irq_of_parse_and_map(np, i);
++              if (pc->irq[i] == 0)
++                      break;
+               pc->irq_data[i].pc = pc;
+               pc->irq_data[i].irqgroup = i;
diff --git a/target/linux/brcm2708/patches-4.4/0012-spi-bcm2835-Support-pin-groups-other-than-7-11.patch b/target/linux/brcm2708/patches-4.4/0012-spi-bcm2835-Support-pin-groups-other-than-7-11.patch
new file mode 100644 (file)
index 0000000..73e2781
--- /dev/null
@@ -0,0 +1,80 @@
+From bc9d2c297e886dfcc340414a61de970942ad7319 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 24 Jun 2015 14:10:44 +0100
+Subject: [PATCH 012/127] spi-bcm2835: Support pin groups other than 7-11
+
+The spi-bcm2835 driver automatically uses GPIO chip-selects due to
+some unreliability of the native ones. In doing so it chooses the
+same pins as the native chip-selects would use, but the existing
+code always uses pins 7 and 8, wherever the SPI function is mapped.
+
+Search the pinctrl group assigned to the driver for pins that
+correspond to native chip-selects, and use those for GPIO chip-
+selects.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/spi/spi-bcm2835.c | 45 +++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 37 insertions(+), 8 deletions(-)
+
+--- a/drivers/spi/spi-bcm2835.c
++++ b/drivers/spi/spi-bcm2835.c
+@@ -688,6 +688,8 @@ static int bcm2835_spi_setup(struct spi_
+ {
+       int err;
+       struct gpio_chip *chip;
++      struct device_node *pins;
++      u32 pingroup_index;
+       /*
+        * sanity checking the native-chipselects
+        */
+@@ -704,15 +706,42 @@ static int bcm2835_spi_setup(struct spi_
+                       "setup: only two native chip-selects are supported\n");
+               return -EINVAL;
+       }
+-      /* now translate native cs to GPIO */
+-      /* get the gpio chip for the base */
+-      chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
+-      if (!chip)
+-              return 0;
++      /* now translate native cs to GPIO */
++      /* first look for chip select pins in the devices pin groups */
++      for (pingroup_index = 0;
++           (pins = of_parse_phandle(spi->master->dev.of_node,
++                                   "pinctrl-0",
++                                    pingroup_index)) != 0;
++           pingroup_index++) {
++              u32 pin;
++              u32 pin_index;
++              for (pin_index = 0;
++                   of_property_read_u32_index(pins,
++                                              "brcm,pins",
++                                              pin_index,
++                                              &pin) == 0;
++                   pin_index++) {
++                      if (((spi->chip_select == 0) &&
++                           ((pin == 8) || (pin == 36) || (pin == 46))) ||
++                          ((spi->chip_select == 1) &&
++                           ((pin == 7) || (pin == 35)))) {
++                              spi->cs_gpio = pin;
++                              break;
++                      }
++              }
++              of_node_put(pins);
++      }
++      /* if that fails, assume GPIOs 7-11 are used */
++      if (!gpio_is_valid(spi->cs_gpio) ) {
++              /* get the gpio chip for the base */
++              chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
++              if (!chip)
++                      return 0;
+-      /* and calculate the real CS */
+-      spi->cs_gpio = chip->base + 8 - spi->chip_select;
++              /* and calculate the real CS */
++              spi->cs_gpio = chip->base + 8 - spi->chip_select;
++      }
+       /* and set up the "mode" and level */
+       dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n",
diff --git a/target/linux/brcm2708/patches-4.4/0013-ARM-bcm2835-Set-Serial-number-and-Revision.patch b/target/linux/brcm2708/patches-4.4/0013-ARM-bcm2835-Set-Serial-number-and-Revision.patch
new file mode 100644 (file)
index 0000000..e2b55b6
--- /dev/null
@@ -0,0 +1,58 @@
+From e04c4837cde13f4782fc5a274599f580d8a29715 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Wed, 3 Jun 2015 12:26:13 +0200
+Subject: [PATCH 013/127] ARM: bcm2835: Set Serial number and Revision
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The VideoCore bootloader passes in Serial number and
+Revision number through Device Tree. Make these available to
+userspace through /proc/cpuinfo.
+
+Mainline status:
+
+There is a commit in linux-next that standardize passing the serial
+number through Device Tree (string: /serial-number):
+ARM: 8355/1: arch: Show the serial number from devicetree in cpuinfo
+
+There was an attempt to do the same with the revision number, but it
+didn't get in:
+[PATCH v2 1/2] arm: devtree: Set system_rev from DT revision
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -17,12 +17,16 @@
+ #include <linux/of_address.h>
+ #include <linux/of_platform.h>
+ #include <linux/clk/bcm2835.h>
++#include <asm/system_info.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+ static void __init bcm2835_init(void)
+ {
++      struct device_node *np = of_find_node_by_path("/system");
++      u32 val;
++      u64 val64;
+       int ret;
+       bcm2835_init_clocks();
+@@ -33,6 +37,11 @@ static void __init bcm2835_init(void)
+               pr_err("of_platform_populate failed: %d\n", ret);
+               BUG();
+       }
++
++      if (!of_property_read_u32(np, "linux,revision", &val))
++              system_rev = val;
++      if (!of_property_read_u64(np, "linux,serial", &val64))
++              system_serial_low = val64;
+ }
+ static const char * const bcm2835_compat[] = {
diff --git a/target/linux/brcm2708/patches-4.4/0014-bcm2835-i2s-get-base-address-for-DMA-from-devicetree.patch b/target/linux/brcm2708/patches-4.4/0014-bcm2835-i2s-get-base-address-for-DMA-from-devicetree.patch
new file mode 100644 (file)
index 0000000..0c36bda
--- /dev/null
@@ -0,0 +1,65 @@
+From c8225021ad8a8e8d2b4560bed644c5552f9f6684 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sun, 11 Oct 2015 16:44:05 +0200
+Subject: [PATCH 014/127] bcm2835-i2s: get base address for DMA from devicetree
+
+Code copied from spi-bcm2835. Get physical address from devicetree
+instead of using hardcoded constant.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -38,6 +38,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/clk.h>
++#include <linux/of_address.h>
+ #include <sound/core.h>
+ #include <sound/pcm.h>
+@@ -158,10 +159,6 @@ static const unsigned int bcm2835_clk_fr
+ #define BCM2835_I2S_INT_RXR           BIT(1)
+ #define BCM2835_I2S_INT_TXW           BIT(0)
+-/* I2S DMA interface */
+-/* FIXME: Needs IOMMU support */
+-#define BCM2835_VCMMU_SHIFT           (0x7E000000 - 0x20000000)
+-
+ /* General device struct */
+ struct bcm2835_i2s_dev {
+       struct device                           *dev;
+@@ -791,6 +788,15 @@ static int bcm2835_i2s_probe(struct plat
+       int ret;
+       struct regmap *regmap[2];
+       struct resource *mem[2];
++      const __be32 *addr;
++      dma_addr_t dma_reg_base;
++
++      addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
++      if (!addr) {
++              dev_err(&pdev->dev, "could not get DMA-register address\n");
++              return -ENODEV;
++      }
++      dma_reg_base = be32_to_cpup(addr);
+       /* Request both ioareas */
+       for (i = 0; i <= 1; i++) {
+@@ -817,12 +823,10 @@ static int bcm2835_i2s_probe(struct plat
+       /* Set the DMA address */
+       dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
+-              (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+-                                        + BCM2835_VCMMU_SHIFT;
++              dma_reg_base + BCM2835_I2S_FIFO_A_REG;
+       dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
+-              (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+-                                        + BCM2835_VCMMU_SHIFT;
++              dma_reg_base + BCM2835_I2S_FIFO_A_REG;
+       /* Set the bus width */
+       dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
diff --git a/target/linux/brcm2708/patches-4.4/0015-bcm2835-i2s-add-24bit-support-update-bclk_ratio-to-m.patch b/target/linux/brcm2708/patches-4.4/0015-bcm2835-i2s-add-24bit-support-update-bclk_ratio-to-m.patch
new file mode 100644 (file)
index 0000000..b627327
--- /dev/null
@@ -0,0 +1,79 @@
+From 328b2e8b8a38fe62431c2ad5ae22cee31740b10d Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sun, 11 Oct 2015 15:21:16 +0200
+Subject: [PATCH 015/127] bcm2835-i2s: add 24bit support, update bclk_ratio to
+ more correct values
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit 62c05a0b5328d9376d39c9e74da10b8a2465c234 ("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:
+
+MMAP is not supported. Claiming this leads to strange issues
+when the format of driver and file do not match.
+
+The datasheet states that the width extension bit should be set
+for widths greater than 24, but greater or equal would be correct.
+This follows from the definition of the width field.
+
+Signed-off-by: Florian Meier <florian.meier@koalo.de>
+
+RPi commit 3e8c672bc4e92d457aa4654bbb4cfd79a18a2327 ("bcm2708-i2s:
+Update bclk_ratio to more correct values")
+
+Discussion about blck_ratio affecting sound quality:
+https://github.com/raspberrypi/linux/issues/681
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -340,11 +340,15 @@ static int bcm2835_i2s_hw_params(struct
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               data_length = 16;
+-              bclk_ratio = 40;
++              bclk_ratio = 50;
++              break;
++      case SNDRV_PCM_FORMAT_S24_LE:
++              data_length = 24;
++              bclk_ratio = 50;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               data_length = 32;
+-              bclk_ratio = 80;
++              bclk_ratio = 100;
+               break;
+       default:
+               return -EINVAL;
+@@ -420,7 +424,7 @@ static int bcm2835_i2s_hw_params(struct
+       /* Setup the frame format */
+       format = BCM2835_I2S_CHEN;
+-      if (data_length > 24)
++      if (data_length >= 24)
+               format |= BCM2835_I2S_CHWEX;
+       format |= BCM2835_I2S_CHWID((data_length-8)&0xf);
+@@ -711,6 +715,7 @@ static struct snd_soc_dai_driver bcm2835
+               .channels_max = 2,
+               .rates =        SNDRV_PCM_RATE_8000_192000,
+               .formats =      SNDRV_PCM_FMTBIT_S16_LE
++                              | SNDRV_PCM_FMTBIT_S24_LE
+                               | SNDRV_PCM_FMTBIT_S32_LE
+               },
+       .capture = {
+@@ -718,6 +723,7 @@ static struct snd_soc_dai_driver bcm2835
+               .channels_max = 2,
+               .rates =        SNDRV_PCM_RATE_8000_192000,
+               .formats =      SNDRV_PCM_FMTBIT_S16_LE
++                              | SNDRV_PCM_FMTBIT_S24_LE
+                               | SNDRV_PCM_FMTBIT_S32_LE
+               },
+       .ops = &bcm2835_i2s_dai_ops,
diff --git a/target/linux/brcm2708/patches-4.4/0016-bcm2835-i2s-setup-clock-only-if-CPU-is-clock-master.patch b/target/linux/brcm2708/patches-4.4/0016-bcm2835-i2s-setup-clock-only-if-CPU-is-clock-master.patch
new file mode 100644 (file)
index 0000000..e096656
--- /dev/null
@@ -0,0 +1,54 @@
+From fce554c6331b34458db54722cb06eb517a32b305 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sun, 11 Oct 2015 15:25:51 +0200
+Subject: [PATCH 016/127] bcm2835-i2s: setup clock only if CPU is clock master
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit c14827ecdaa36607f6110f9ce8df96e698672191 ("bcm2708: Allow
+option card devices to be configured via DT")
+
+Original work by Zoltan Szenczi, committed to RPi tree by
+Phil Elwell.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -411,15 +411,25 @@ static int bcm2835_i2s_hw_params(struct
+               divf = dividend & BCM2835_CLK_DIVF_MASK;
+       }
+-      /* Set clock divider */
+-      regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD
+-                      | BCM2835_CLK_DIVI(divi)
+-                      | BCM2835_CLK_DIVF(divf));
++      /* Clock should only be set up here if CPU is clock master */
++      switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++      case SND_SOC_DAIFMT_CBS_CFS:
++      case SND_SOC_DAIFMT_CBS_CFM:
++              /* Set clock divider */
++              regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG,
++                                BCM2835_CLK_PASSWD
++                              | BCM2835_CLK_DIVI(divi)
++                              | BCM2835_CLK_DIVF(divf));
+-      /* Setup clock, but don't start it yet */
+-      regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD
+-                      | BCM2835_CLK_MASH(mash)
+-                      | BCM2835_CLK_SRC(clk_src));
++              /* Setup clock, but don't start it yet */
++              regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
++                                BCM2835_CLK_PASSWD
++                              | BCM2835_CLK_MASH(mash)
++                              | BCM2835_CLK_SRC(clk_src));
++              break;
++      default:
++              break;
++      }
+       /* Setup the frame format */
+       format = BCM2835_I2S_CHEN;
diff --git a/target/linux/brcm2708/patches-4.4/0017-bcm2835-i2s-Eliminate-debugfs-directory-error.patch b/target/linux/brcm2708/patches-4.4/0017-bcm2835-i2s-Eliminate-debugfs-directory-error.patch
new file mode 100644 (file)
index 0000000..1caa347
--- /dev/null
@@ -0,0 +1,36 @@
+From 45995262bd8d5194e9430d2a826c84ed28c408eb Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sun, 11 Oct 2015 15:49:51 +0200
+Subject: [PATCH 017/127] bcm2835-i2s: Eliminate debugfs directory error
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit fd7d7a3dbe9262d16971ef81c234ed28c6499dd7 ("bcm2708:
+Eliminate i2s debugfs directory error")
+
+Qualify the two regmap ranges uses by bcm2708-i2s ('-i2s' and '-clk')
+to avoid the name clash when registering debugfs entries.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -782,6 +782,7 @@ static const struct regmap_config bcm283
+               .precious_reg = bcm2835_i2s_precious_reg,
+               .volatile_reg = bcm2835_i2s_volatile_reg,
+               .cache_type = REGCACHE_RBTREE,
++              .name = "i2s",
+       },
+       {
+               .reg_bits = 32,
+@@ -790,6 +791,7 @@ static const struct regmap_config bcm283
+               .max_register = BCM2835_CLK_PCMDIV_REG,
+               .volatile_reg = bcm2835_clk_volatile_reg,
+               .cache_type = REGCACHE_RBTREE,
++              .name = "clk",
+       },
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0018-bcm2835-i2s-Register-PCM-device.patch b/target/linux/brcm2708/patches-4.4/0018-bcm2835-i2s-Register-PCM-device.patch
new file mode 100644 (file)
index 0000000..eeb7d61
--- /dev/null
@@ -0,0 +1,63 @@
+From b58d4ef09eca4674d1530f0c8e1ca074b269ebea Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sun, 11 Oct 2015 15:35:20 +0200
+Subject: [PATCH 018/127] bcm2835-i2s: Register PCM device
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit ba46b4935a23aa2caac1855ead52a035d4776680 ("ASoC: Add
+support for BCM2708")
+
+This driver adds support for digital audio (I2S)
+for the BCM2708 SoC that is used by the
+Raspberry Pi. External audio codecs can be
+connected to the Raspberry Pi via P5 header.
+
+It relies on cyclic DMA engine support for BCM2708.
+
+Signed-off-by: Florian Meier <florian.meier@koalo.de>
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -799,6 +799,25 @@ static const struct snd_soc_component_dr
+       .name           = "bcm2835-i2s-comp",
+ };
++static const struct snd_pcm_hardware bcm2835_pcm_hardware = {
++      .info                   = SNDRV_PCM_INFO_INTERLEAVED |
++                                SNDRV_PCM_INFO_JOINT_DUPLEX,
++      .formats                = SNDRV_PCM_FMTBIT_S16_LE |
++                                SNDRV_PCM_FMTBIT_S24_LE |
++                                SNDRV_PCM_FMTBIT_S32_LE,
++      .period_bytes_min       = 32,
++      .period_bytes_max       = 64 * PAGE_SIZE,
++      .periods_min            = 2,
++      .periods_max            = 255,
++      .buffer_bytes_max       = 128 * PAGE_SIZE,
++};
++
++static const struct snd_dmaengine_pcm_config bcm2835_dmaengine_pcm_config = {
++      .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
++      .pcm_hardware = &bcm2835_pcm_hardware,
++      .prealloc_buffer_size = 256 * PAGE_SIZE,
++};
++
+ static int bcm2835_i2s_probe(struct platform_device *pdev)
+ {
+       struct bcm2835_i2s_dev *dev;
+@@ -870,7 +889,9 @@ static int bcm2835_i2s_probe(struct plat
+               return ret;
+       }
+-      ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
++      ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
++                      &bcm2835_dmaengine_pcm_config,
++                      SND_DMAENGINE_PCM_FLAG_COMPAT);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+               return ret;
diff --git a/target/linux/brcm2708/patches-4.4/0019-bcm2835-i2s-Enable-MMAP-support-via-a-DT-property.patch b/target/linux/brcm2708/patches-4.4/0019-bcm2835-i2s-Enable-MMAP-support-via-a-DT-property.patch
new file mode 100644 (file)
index 0000000..c422cc7
--- /dev/null
@@ -0,0 +1,44 @@
+From 61f155e164c5dbfa5cec9a099e4aa802c2155423 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sun, 11 Oct 2015 15:55:21 +0200
+Subject: [PATCH 019/127] bcm2835-i2s: Enable MMAP support via a DT property
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit 7ee829fd77a30127db5d0b3c7d79b8718166e568 ("bcm2708-i2s:
+Enable MMAP support via a DT property and overlay")
+
+The i2s driver used to claim to support MMAP, but that feature was disabled
+when some problems were found. Add the ability to enable this feature
+through Device Tree, using the i2s-mmap overlay.
+
+See: #1004
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -799,7 +799,7 @@ static const struct snd_soc_component_dr
+       .name           = "bcm2835-i2s-comp",
+ };
+-static const struct snd_pcm_hardware bcm2835_pcm_hardware = {
++static struct snd_pcm_hardware bcm2835_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_JOINT_DUPLEX,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+@@ -835,6 +835,11 @@ static int bcm2835_i2s_probe(struct plat
+       }
+       dma_reg_base = be32_to_cpup(addr);
++      if (of_property_read_bool(pdev->dev.of_node, "brcm,enable-mmap"))
++              bcm2835_pcm_hardware.info |=
++                      SNDRV_PCM_INFO_MMAP |
++                      SNDRV_PCM_INFO_MMAP_VALID;
++
+       /* Request both ioareas */
+       for (i = 0; i <= 1; i++) {
+               void __iomem *base;
diff --git a/target/linux/brcm2708/patches-4.4/0020-dmaengine-bcm2835-Add-slave-dma-support.patch b/target/linux/brcm2708/patches-4.4/0020-dmaengine-bcm2835-Add-slave-dma-support.patch
new file mode 100644 (file)
index 0000000..c49e482
--- /dev/null
@@ -0,0 +1,320 @@
+From 780a1039ccfd293d583742a4f2326997b15f5aff Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Thu, 9 Apr 2015 12:34:11 +0200
+Subject: [PATCH 020/127] dmaengine: bcm2835: Add slave dma support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add slave transfer capability to BCM2835 dmaengine driver.
+This patch is pulled from the bcm2708-dmaengine driver in the
+Raspberry Pi repo. The work was done by Gellert Weisz.
+
+Tested using the bcm2835-mmc driver from the same repo.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/dma/bcm2835-dma.c | 206 ++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 192 insertions(+), 14 deletions(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -1,11 +1,10 @@
+ /*
+  * BCM2835 DMA engine support
+  *
+- * This driver only supports cyclic DMA transfers
+- * as needed for the I2S module.
+- *
+  * Author:      Florian Meier <florian.meier@koalo.de>
+  *              Copyright 2013
++ *              Gellert Weisz <gellert@raspberrypi.org>
++ *              Copyright 2013-2014
+  *
+  * Based on
+  *    OMAP DMAengine support by Russell King
+@@ -95,6 +94,8 @@ struct bcm2835_desc {
+       size_t size;
+ };
++#define BCM2835_DMA_WAIT_CYCLES       0  /* Slow down DMA transfers: 0-31 */
++
+ #define BCM2835_DMA_CS                0x00
+ #define BCM2835_DMA_ADDR      0x04
+ #define BCM2835_DMA_SOURCE_AD 0x0c
+@@ -111,12 +112,16 @@ struct bcm2835_desc {
+ #define BCM2835_DMA_RESET     BIT(31) /* WO, self clearing */
+ #define BCM2835_DMA_INT_EN    BIT(0)
++#define BCM2835_DMA_WAIT_RESP BIT(3)
+ #define BCM2835_DMA_D_INC     BIT(4)
++#define BCM2835_DMA_D_WIDTH   BIT(5)
+ #define BCM2835_DMA_D_DREQ    BIT(6)
+ #define BCM2835_DMA_S_INC     BIT(8)
++#define BCM2835_DMA_S_WIDTH   BIT(9)
+ #define BCM2835_DMA_S_DREQ    BIT(10)
+ #define BCM2835_DMA_PER_MAP(x)        ((x) << 16)
++#define BCM2835_DMA_WAITS(x)  (((x) & 0x1f) << 21)
+ #define BCM2835_DMA_DATA_TYPE_S8      1
+ #define BCM2835_DMA_DATA_TYPE_S16     2
+@@ -130,6 +135,14 @@ struct bcm2835_desc {
+ #define BCM2835_DMA_CHAN(n)   ((n) << 8) /* Base address */
+ #define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
++#define MAX_NORMAL_TRANSFER   SZ_1G
++/*
++ * Max length on a Lite channel is 65535 bytes.
++ * DMA handles byte-enables on SDRAM reads and writes even on 128-bit accesses,
++ * but byte-enables don't exist on peripheral addresses, so align to 32-bit.
++ */
++#define MAX_LITE_TRANSFER     (SZ_64K - 4)
++
+ static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d)
+ {
+       return container_of(d, struct bcm2835_dmadev, ddev);
+@@ -226,12 +239,18 @@ static irqreturn_t bcm2835_dma_callback(
+       d = c->desc;
+       if (d) {
+-              /* TODO Only works for cyclic DMA */
+-              vchan_cyclic_callback(&d->vd);
+-      }
++              if (c->cyclic) {
++                      vchan_cyclic_callback(&d->vd);
+-      /* Keep the DMA engine running */
+-      writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
++                      /* Keep the DMA engine running */
++                      writel(BCM2835_DMA_ACTIVE,
++                             c->chan_base + BCM2835_DMA_CS);
++
++              } else {
++                      vchan_cookie_complete(&c->desc->vd);
++                      bcm2835_dma_start_desc(c);
++              }
++      }
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+@@ -339,8 +358,6 @@ static void bcm2835_dma_issue_pending(st
+       struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+       unsigned long flags;
+-      c->cyclic = true; /* Nothing else is implemented */
+-
+       spin_lock_irqsave(&c->vc.lock, flags);
+       if (vchan_issue_pending(&c->vc) && !c->desc)
+               bcm2835_dma_start_desc(c);
+@@ -358,7 +375,7 @@ static struct dma_async_tx_descriptor *b
+       struct bcm2835_desc *d;
+       dma_addr_t dev_addr;
+       unsigned int es, sync_type;
+-      unsigned int frame;
++      unsigned int frame, max_size;
+       int i;
+       /* Grab configuration */
+@@ -393,7 +410,12 @@ static struct dma_async_tx_descriptor *b
+       d->c = c;
+       d->dir = direction;
+-      d->frames = buf_len / period_len;
++      if (c->ch >= 8) /* LITE channel */
++              max_size = MAX_LITE_TRANSFER;
++      else
++              max_size = MAX_NORMAL_TRANSFER;
++      period_len = min(period_len, max_size);
++      d->frames = (buf_len - 1) / (period_len + 1);
+       d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL);
+       if (!d->cb_list) {
+@@ -441,17 +463,171 @@ static struct dma_async_tx_descriptor *b
+                               BCM2835_DMA_PER_MAP(c->dreq);
+               /* Length of a frame */
+-              control_block->length = period_len;
++              if (frame != d->frames - 1)
++                      control_block->length = period_len;
++              else
++                      control_block->length = buf_len - (d->frames - 1) *
++                                              period_len;
+               d->size += control_block->length;
+               /*
+                * Next block is the next frame.
+-               * This DMA engine driver currently only supports cyclic DMA.
++               * This function is called on cyclic DMA transfers.
+                * Therefore, wrap around at number of frames.
+                */
+               control_block->next = d->cb_list[((frame + 1) % d->frames)].paddr;
+       }
++      c->cyclic = true;
++
++      return vchan_tx_prep(&c->vc, &d->vd, flags);
++}
++
++static struct dma_async_tx_descriptor *
++bcm2835_dma_prep_slave_sg(struct dma_chan *chan,
++                        struct scatterlist *sgl,
++                        unsigned int sg_len,
++                        enum dma_transfer_direction direction,
++                        unsigned long flags, void *context)
++{
++      struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
++      enum dma_slave_buswidth dev_width;
++      struct bcm2835_desc *d;
++      dma_addr_t dev_addr;
++      struct scatterlist *sgent;
++      unsigned int i, sync_type, split_cnt, max_size;
++
++      if (!is_slave_direction(direction)) {
++              dev_err(chan->device->dev, "direction not supported\n");
++              return NULL;
++      }
++
++      if (direction == DMA_DEV_TO_MEM) {
++              dev_addr = c->cfg.src_addr;
++              dev_width = c->cfg.src_addr_width;
++              sync_type = BCM2835_DMA_S_DREQ;
++      } else {
++              dev_addr = c->cfg.dst_addr;
++              dev_width = c->cfg.dst_addr_width;
++              sync_type = BCM2835_DMA_D_DREQ;
++      }
++
++      /* Bus width translates to the element size (ES) */
++      switch (dev_width) {
++      case DMA_SLAVE_BUSWIDTH_4_BYTES:
++              break;
++      default:
++              dev_err(chan->device->dev, "buswidth not supported: %i\n",
++                      dev_width);
++              return NULL;
++      }
++
++      /* Allocate and setup the descriptor. */
++      d = kzalloc(sizeof(*d), GFP_NOWAIT);
++      if (!d)
++              return NULL;
++
++      d->dir = direction;
++
++      if (c->ch >= 8) /* LITE channel */
++              max_size = MAX_LITE_TRANSFER;
++      else
++              max_size = MAX_NORMAL_TRANSFER;
++
++      /*
++       * Store the length of the SG list in d->frames
++       * taking care to account for splitting up transfers
++       * too large for a LITE channel
++       */
++      d->frames = 0;
++      for_each_sg(sgl, sgent, sg_len, i) {
++              unsigned int len = sg_dma_len(sgent);
++
++              d->frames += len / max_size + 1;
++      }
++
++      /* Allocate memory for control blocks */
++      d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb);
++      d->control_block_base = dma_zalloc_coherent(chan->device->dev,
++                      d->control_block_size, &d->control_block_base_phys,
++                      GFP_NOWAIT);
++      if (!d->control_block_base) {
++              kfree(d);
++              return NULL;
++      }
++
++      /*
++       * Iterate over all SG entries, create a control block
++       * for each frame and link them together.
++       * Count the number of times an SG entry had to be split
++       * as a result of using a LITE channel
++       */
++      split_cnt = 0;
++
++      for_each_sg(sgl, sgent, sg_len, i) {
++              unsigned int j;
++              dma_addr_t addr = sg_dma_address(sgent);
++              unsigned int len = sg_dma_len(sgent);
++
++              for (j = 0; j < len; j += max_size) {
++                      struct bcm2835_dma_cb *control_block =
++                              &d->control_block_base[i + split_cnt];
++
++                      /* Setup addresses */
++                      if (d->dir == DMA_DEV_TO_MEM) {
++                              control_block->info = BCM2835_DMA_D_INC |
++                                                    BCM2835_DMA_D_WIDTH |
++                                                    BCM2835_DMA_S_DREQ;
++                              control_block->src = dev_addr;
++                              control_block->dst = addr + (dma_addr_t)j;
++                      } else {
++                              control_block->info = BCM2835_DMA_S_INC |
++                                                    BCM2835_DMA_S_WIDTH |
++                                                    BCM2835_DMA_D_DREQ;
++                              control_block->src = addr + (dma_addr_t)j;
++                              control_block->dst = dev_addr;
++                      }
++
++                      /* Common part */
++                      control_block->info |=
++                              BCM2835_DMA_WAITS(BCM2835_DMA_WAIT_CYCLES);
++                      control_block->info |= BCM2835_DMA_WAIT_RESP;
++
++                      /* Enable */
++                      if (i == sg_len - 1 && len - j <= max_size)
++                              control_block->info |= BCM2835_DMA_INT_EN;
++
++                      /* Setup synchronization */
++                      if (sync_type)
++                              control_block->info |= sync_type;
++
++                      /* Setup DREQ channel */
++                      if (c->dreq)
++                              control_block->info |=
++                                      BCM2835_DMA_PER_MAP(c->dreq);
++
++                      /* Length of a frame */
++                      control_block->length = min(len - j, max_size);
++                      d->size += control_block->length;
++
++                      if (i < sg_len - 1 || len - j > max_size) {
++                              /* Next block is the next frame. */
++                              control_block->next =
++                                      d->control_block_base_phys +
++                                      sizeof(struct bcm2835_dma_cb) *
++                                      (i + split_cnt + 1);
++                      } else {
++                              /* Next block is empty. */
++                              control_block->next = 0;
++                      }
++
++                      if (len - j > max_size)
++                              split_cnt++;
++              }
++      }
++
++      c->cyclic = false;
++
+       return vchan_tx_prep(&c->vc, &d->vd, flags);
+ error_cb:
+       i--;
+@@ -620,6 +796,7 @@ static int bcm2835_dma_probe(struct plat
+       od->ddev.device_tx_status = bcm2835_dma_tx_status;
+       od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
+       od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
++      od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg;
+       od->ddev.device_config = bcm2835_dma_slave_config;
+       od->ddev.device_terminate_all = bcm2835_dma_terminate_all;
+       od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+@@ -708,4 +885,5 @@ module_platform_driver(bcm2835_dma_drive
+ MODULE_ALIAS("platform:bcm2835-dma");
+ MODULE_DESCRIPTION("BCM2835 DMA engine driver");
+ MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
++MODULE_AUTHOR("Gellert Weisz <gellert@raspberrypi.org>");
+ MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0021-dmaengine-bcm2835-set-residue_granularity-field.patch b/target/linux/brcm2708/patches-4.4/0021-dmaengine-bcm2835-set-residue_granularity-field.patch
new file mode 100644 (file)
index 0000000..1e562ce
--- /dev/null
@@ -0,0 +1,29 @@
+From 6ff0d626e7d84df71f6bc75e2c5ed35c42858bcc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Sat, 3 Oct 2015 15:58:59 +0200
+Subject: [PATCH 021/127] dmaengine: bcm2835: set residue_granularity field
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+bcm2835-dma supports residue reporting at burst level but didn't report
+this via the residue_granularity field.
+
+Without this field set properly we get playback issues with I2S cards.
+
+[by HiassofT, taken from bcm2708-dmaengine]
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/dma/bcm2835-dma.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -802,6 +802,7 @@ static int bcm2835_dma_probe(struct plat
+       od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+       od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+       od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
++      od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+       od->ddev.dev = &pdev->dev;
+       INIT_LIST_HEAD(&od->ddev.channels);
+       spin_lock_init(&od->lock);
diff --git a/target/linux/brcm2708/patches-4.4/0022-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch b/target/linux/brcm2708/patches-4.4/0022-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch
new file mode 100644 (file)
index 0000000..e3c9595
--- /dev/null
@@ -0,0 +1,98 @@
+From 16dc5e0535e48ce3e9c6995c87118e9e7b5b775a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Sat, 3 Oct 2015 22:22:55 +0200
+Subject: [PATCH 022/127] dmaengine: bcm2835: Load driver early and support
+ legacy API
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Load driver early since at least bcm2708_fb doesn't support deferred
+probing and even if it did, we don't want the video driver deferred.
+Support the legacy DMA API which is needed by bcm2708_fb.
+Don't mask out channel 2.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/dma/Kconfig       |  2 +-
+ drivers/dma/bcm2835-dma.c | 30 ++++++++++++++++++++++++------
+ 2 files changed, 25 insertions(+), 7 deletions(-)
+
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -108,7 +108,7 @@ config COH901318
+ config DMA_BCM2835
+       tristate "BCM2835 DMA engine support"
+-      depends on ARCH_BCM2835
++      depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -36,6 +36,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/list.h>
+ #include <linux/module.h>
++#include <linux/platform_data/dma-bcm2708.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+ #include <linux/io.h>
+@@ -786,6 +787,10 @@ static int bcm2835_dma_probe(struct plat
+       if (IS_ERR(base))
+               return PTR_ERR(base);
++      rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
++      if (rc)
++              dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
++
+       od->base = base;
+       dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
+@@ -818,11 +823,8 @@ static int bcm2835_dma_probe(struct plat
+               goto err_no_dma;
+       }
+-      /*
+-       * Do not use the FIQ and BULK channels,
+-       * because they are used by the GPU.
+-       */
+-      chans_available &= ~(BCM2835_DMA_FIQ_MASK | BCM2835_DMA_BULK_MASK);
++      /* Channel 0 is used by the legacy API */
++      chans_available &= ~BCM2835_DMA_BULK_MASK;
+       for (i = 0; i < pdev->num_resources; i++) {
+               irq = platform_get_irq(pdev, i);
+@@ -866,6 +868,7 @@ static int bcm2835_dma_remove(struct pla
+ {
+       struct bcm2835_dmadev *od = platform_get_drvdata(pdev);
++      bcm_dmaman_remove(pdev);
+       dma_async_device_unregister(&od->ddev);
+       bcm2835_dma_free(od);
+@@ -881,7 +884,22 @@ static struct platform_driver bcm2835_dm
+       },
+ };
+-module_platform_driver(bcm2835_dma_driver);
++static int bcm2835_dma_init(void)
++{
++      return platform_driver_register(&bcm2835_dma_driver);
++}
++
++static void bcm2835_dma_exit(void)
++{
++      platform_driver_unregister(&bcm2835_dma_driver);
++}
++
++/*
++ * Load after serial driver (arch_initcall) so we see the messages if it fails,
++ * but before drivers (module_init) that need a DMA channel.
++ */
++subsys_initcall(bcm2835_dma_init);
++module_exit(bcm2835_dma_exit);
+ MODULE_ALIAS("platform:bcm2835-dma");
+ MODULE_DESCRIPTION("BCM2835 DMA engine driver");
diff --git a/target/linux/brcm2708/patches-4.4/0023-bcm2835-dma-Fix-dreq-not-set-for-slave-transfers.patch b/target/linux/brcm2708/patches-4.4/0023-bcm2835-dma-Fix-dreq-not-set-for-slave-transfers.patch
new file mode 100644 (file)
index 0000000..42cf9fd
--- /dev/null
@@ -0,0 +1,21 @@
+From 50eef5c715b894683aebf81332c82426dc10f8cb Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sat, 10 Oct 2015 12:29:18 +0200
+Subject: [PATCH 023/127] bcm2835-dma: Fix dreq not set for slave transfers
+
+Set dreq to slave_id if it is not set like in bcm2708-dmaengine.
+---
+ drivers/dma/bcm2835-dma.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -657,6 +657,8 @@ static int bcm2835_dma_slave_config(stru
+       }
+       c->cfg = *cfg;
++      if (!c->dreq)
++              c->dreq = cfg->slave_id;
+       return 0;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0024-bcm2835-dma-Limit-cyclic-transfers-on-lite-channels-.patch b/target/linux/brcm2708/patches-4.4/0024-bcm2835-dma-Limit-cyclic-transfers-on-lite-channels-.patch
new file mode 100644 (file)
index 0000000..4461fec
--- /dev/null
@@ -0,0 +1,37 @@
+From c7e464c38d38ad59899c94dfad6c3455c18f7d76 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sun, 11 Oct 2015 12:28:30 +0200
+Subject: [PATCH 024/127] bcm2835-dma: Limit cyclic transfers on lite channels
+ to 32k
+
+Transfers larger than 32k cause repeated clicking with I2S soundcards.
+The exact reason is yet unknown, so limit to 32k as bcm2708-dmaengine
+did as an intermediate fix.
+---
+ drivers/dma/bcm2835-dma.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -144,6 +144,12 @@ struct bcm2835_desc {
+  */
+ #define MAX_LITE_TRANSFER     (SZ_64K - 4)
++/*
++ * Transfers larger than 32k cause issues with the bcm2708-i2s driver,
++ * so limit transfer size to 32k as bcm2708-dmaengine did.
++ */
++#define MAX_CYCLIC_LITE_TRANSFER      SZ_32K
++
+ static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d)
+ {
+       return container_of(d, struct bcm2835_dmadev, ddev);
+@@ -412,7 +418,7 @@ static struct dma_async_tx_descriptor *b
+       d->c = c;
+       d->dir = direction;
+       if (c->ch >= 8) /* LITE channel */
+-              max_size = MAX_LITE_TRANSFER;
++              max_size = MAX_CYCLIC_LITE_TRANSFER;
+       else
+               max_size = MAX_NORMAL_TRANSFER;
+       period_len = min(period_len, max_size);
diff --git a/target/linux/brcm2708/patches-4.4/0025-bcm2835-Add-support-for-uart1.patch b/target/linux/brcm2708/patches-4.4/0025-bcm2835-Add-support-for-uart1.patch
new file mode 100644 (file)
index 0000000..cd7f242
--- /dev/null
@@ -0,0 +1,57 @@
+From 34cb40cb97cd3080d3d0f314b2b063939b90c069 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Sat, 15 Aug 2015 20:50:02 +0200
+Subject: [PATCH 025/127] bcm2835: Add support for uart1
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is a hack until a proper solution is agreed upon.
+Martin Sperl is doing some work in this area.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -22,6 +22,29 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
++/* Use this hack until a proper solution is agreed upon */
++static void __init bcm2835_init_uart1(void)
++{
++      struct device_node *np;
++
++      np = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-aux-uart");
++      if (of_device_is_available(np)) {
++              np = of_find_compatible_node(NULL, NULL,
++                                           "bcrm,bcm2835-aux-enable");
++              if (np) {
++                      void __iomem *base = of_iomap(np, 0);
++
++                      if (!base) {
++                              pr_err("bcm2835: Failed enabling Mini UART\n");
++                              return;
++                      }
++
++                      writel(1, base);
++                      pr_info("bcm2835: Mini UART enabled\n");
++              }
++      }
++}
++
+ static void __init bcm2835_init(void)
+ {
+       struct device_node *np = of_find_node_by_path("/system");
+@@ -42,6 +65,8 @@ static void __init bcm2835_init(void)
+               system_rev = val;
+       if (!of_property_read_u64(np, "linux,serial", &val64))
+               system_serial_low = val64;
++
++      bcm2835_init_uart1();
+ }
+ static const char * const bcm2835_compat[] = {
diff --git a/target/linux/brcm2708/patches-4.4/0026-firmware-bcm2835-Add-missing-property-tags.patch b/target/linux/brcm2708/patches-4.4/0026-firmware-bcm2835-Add-missing-property-tags.patch
new file mode 100644 (file)
index 0000000..8bd7be9
--- /dev/null
@@ -0,0 +1,62 @@
+From 40946ea47dd52c827b30d3601f7b393c46fbfcf3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Fri, 26 Jun 2015 14:21:20 +0200
+Subject: [PATCH 026/127] firmware: bcm2835: Add missing property tags
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -63,6 +63,7 @@ enum rpi_firmware_property_tag {
+       RPI_FIRMWARE_GET_MIN_VOLTAGE =                        0x00030008,
+       RPI_FIRMWARE_GET_TURBO =                              0x00030009,
+       RPI_FIRMWARE_GET_MAX_TEMPERATURE =                    0x0003000a,
++      RPI_FIRMWARE_GET_STC =                                0x0003000b,
+       RPI_FIRMWARE_ALLOCATE_MEMORY =                        0x0003000c,
+       RPI_FIRMWARE_LOCK_MEMORY =                            0x0003000d,
+       RPI_FIRMWARE_UNLOCK_MEMORY =                          0x0003000e,
+@@ -72,10 +73,12 @@ enum rpi_firmware_property_tag {
+       RPI_FIRMWARE_SET_ENABLE_QPU =                         0x00030012,
+       RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE =       0x00030014,
+       RPI_FIRMWARE_GET_EDID_BLOCK =                         0x00030020,
++      RPI_FIRMWARE_GET_CUSTOMER_OTP =                       0x00030021,
+       RPI_FIRMWARE_SET_CLOCK_STATE =                        0x00038001,
+       RPI_FIRMWARE_SET_CLOCK_RATE =                         0x00038002,
+       RPI_FIRMWARE_SET_VOLTAGE =                            0x00038003,
+       RPI_FIRMWARE_SET_TURBO =                              0x00038009,
++      RPI_FIRMWARE_SET_CUSTOMER_OTP =                       0x00038021,
+       /* Dispmanx TAGS */
+       RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE =                   0x00040001,
+@@ -89,6 +92,7 @@ enum rpi_firmware_property_tag {
+       RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET =         0x00040009,
+       RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN =               0x0004000a,
+       RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE =                0x0004000b,
++      RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF =               0x0004000f,
+       RPI_FIRMWARE_FRAMEBUFFER_RELEASE =                    0x00048001,
+       RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
+       RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT =  0x00044004,
+@@ -98,6 +102,7 @@ enum rpi_firmware_property_tag {
+       RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET =        0x00044009,
+       RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN =              0x0004400a,
+       RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE =               0x0004400b,
++      RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC =                 0x0004400e,
+       RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT =  0x00048003,
+       RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT =   0x00048004,
+       RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH =                  0x00048005,
+@@ -106,6 +111,9 @@ enum rpi_firmware_property_tag {
+       RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET =         0x00048009,
+       RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN =               0x0004800a,
+       RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE =                0x0004800b,
++      RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC =                  0x0004800e,
++
++      RPI_FIRMWARE_VCHIQ_INIT =                             0x00048010,
+       RPI_FIRMWARE_GET_COMMAND_LINE =                       0x00050001,
+       RPI_FIRMWARE_GET_DMA_CHANNELS =                       0x00060001,
diff --git a/target/linux/brcm2708/patches-4.4/0027-Main-bcm2708-bcm2709-linux-port.patch b/target/linux/brcm2708/patches-4.4/0027-Main-bcm2708-bcm2709-linux-port.patch
new file mode 100644 (file)
index 0000000..56120c6
--- /dev/null
@@ -0,0 +1,2418 @@
+From 75ae3f717d7598a6eb1582097923ee0838a02a8b Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Sun, 12 May 2013 12:24:19 +0100
+Subject: [PATCH 027/127] Main bcm2708/bcm2709 linux port
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ arch/arm/Kconfig                                 |  49 +++
+ arch/arm/Kconfig.debug                           |   8 +
+ arch/arm/Makefile                                |   2 +
+ arch/arm/kernel/head.S                           |   8 +
+ arch/arm/kernel/process.c                        |  10 +
+ arch/arm/mach-bcm2708/Kconfig                    |  23 ++
+ arch/arm/mach-bcm2708/Makefile                   |   5 +
+ arch/arm/mach-bcm2708/Makefile.boot              |   3 +
+ arch/arm/mach-bcm2708/bcm2708.c                  | 231 ++++++++++++
+ arch/arm/mach-bcm2708/include/mach/debug-macro.S |  22 ++
+ arch/arm/mach-bcm2708/include/mach/io.h          |  27 ++
+ arch/arm/mach-bcm2708/include/mach/memory.h      |  57 +++
+ arch/arm/mach-bcm2708/include/mach/platform.h    | 112 ++++++
+ arch/arm/mach-bcm2708/include/mach/system.h      |  37 ++
+ arch/arm/mach-bcm2708/include/mach/uncompress.h  |  84 +++++
+ arch/arm/mach-bcm2708/include/mach/vmalloc.h     |  20 ++
+ arch/arm/mach-bcm2709/Kconfig                    |  16 +
+ arch/arm/mach-bcm2709/Makefile                   |   5 +
+ arch/arm/mach-bcm2709/Makefile.boot              |   3 +
+ arch/arm/mach-bcm2709/bcm2709.c                  | 380 ++++++++++++++++++++
+ arch/arm/mach-bcm2709/include/mach/debug-macro.S |  22 ++
+ arch/arm/mach-bcm2709/include/mach/entry-macro.S | 123 +++++++
+ arch/arm/mach-bcm2709/include/mach/io.h          |  27 ++
+ arch/arm/mach-bcm2709/include/mach/memory.h      |  57 +++
+ arch/arm/mach-bcm2709/include/mach/platform.h    | 188 ++++++++++
+ arch/arm/mach-bcm2709/include/mach/system.h      |  37 ++
+ arch/arm/mach-bcm2709/include/mach/uncompress.h  |  84 +++++
+ arch/arm/mach-bcm2709/include/mach/vc_mem.h      |  35 ++
+ arch/arm/mach-bcm2709/include/mach/vmalloc.h     |  20 ++
+ arch/arm/mach-bcm2709/vc_mem.c                   | 431 +++++++++++++++++++++++
+ arch/arm/mm/Kconfig                              |   2 +-
+ arch/arm/mm/proc-v6.S                            |  15 +-
+ arch/arm/mm/proc-v7.S                            |   1 +
+ arch/arm/tools/mach-types                        |   2 +
+ drivers/clocksource/Makefile                     |   2 +-
+ drivers/irqchip/Makefile                         |   3 +
+ include/linux/mmc/host.h                         |   1 +
+ 37 files changed, 2147 insertions(+), 5 deletions(-)
+ create mode 100644 arch/arm/mach-bcm2708/Kconfig
+ create mode 100644 arch/arm/mach-bcm2708/Makefile
+ create mode 100644 arch/arm/mach-bcm2708/Makefile.boot
+ create mode 100644 arch/arm/mach-bcm2708/bcm2708.c
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/debug-macro.S
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/io.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/memory.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/platform.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/system.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/uncompress.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/vmalloc.h
+ create mode 100644 arch/arm/mach-bcm2709/Kconfig
+ create mode 100644 arch/arm/mach-bcm2709/Makefile
+ create mode 100644 arch/arm/mach-bcm2709/Makefile.boot
+ create mode 100644 arch/arm/mach-bcm2709/bcm2709.c
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/debug-macro.S
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/entry-macro.S
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/io.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/memory.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/platform.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/system.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/uncompress.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/vc_mem.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/vmalloc.h
+ create mode 100644 arch/arm/mach-bcm2709/vc_mem.c
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -317,6 +317,52 @@ choice
+       default ARCH_VERSATILE if !MMU
+       default ARCH_MULTIPLATFORM if MMU
++config ARCH_BCM2708
++      bool "Broadcom BCM2708 family"
++      select CPU_V6
++      select ARM_AMBA
++      select CLKSRC_MMIO
++      select CLKSRC_OF if OF
++      select HAVE_SCHED_CLOCK
++      select NEED_MACH_GPIO_H
++      select NEED_MACH_MEMORY_H
++      select COMMON_CLK
++      select ARCH_HAS_CPUFREQ
++      select GENERIC_CLOCKEVENTS
++      select ARM_ERRATA_411920
++      select MACH_BCM2708
++      select MULTI_IRQ_HANDLER
++      select SPARSE_IRQ
++      select VC4
++      select FIQ
++      help
++        This enables support for Broadcom BCM2708 boards.
++
++config ARCH_BCM2709
++      bool "Broadcom BCM2709 family"
++      select CPU_V7
++      select HAVE_SMP
++      select ARM_AMBA
++      select MIGHT_HAVE_CACHE_L2X0
++      select HAVE_SCHED_CLOCK
++      select NEED_MACH_MEMORY_H
++      select NEED_MACH_IO_H
++      select COMMON_CLK
++      select ARCH_HAS_CPUFREQ
++      select GENERIC_CLOCKEVENTS
++      select MACH_BCM2709
++      select MULTI_IRQ_HANDLER
++      select SPARSE_IRQ
++      select MFD_SYSCON
++      select VC4
++      select FIQ
++      select USE_OF
++      select ARCH_REQUIRE_GPIOLIB
++      select PINCTRL
++      select PINCTRL_BCM2835
++      help
++        This enables support for Broadcom BCM2709 boards.
++
+ config ARCH_MULTIPLATFORM
+       bool "Allow multiple platforms to be selected"
+       depends on MMU
+@@ -808,6 +854,9 @@ config ARCH_VIRT
+ # Kconfigs may be included either alphabetically (according to the
+ # plat- suffix) or along side the corresponding mach-* source.
+ #
++source "arch/arm/mach-bcm2708/Kconfig"
++source "arch/arm/mach-bcm2709/Kconfig"
++
+ source "arch/arm/mach-mvebu/Kconfig"
+ source "arch/arm/mach-alpine/Kconfig"
+--- a/arch/arm/Kconfig.debug
++++ b/arch/arm/Kconfig.debug
+@@ -1241,6 +1241,14 @@ choice
+                 options; the platform specific options are deprecated
+                 and will be soon removed.
++      config DEBUG_BCM2708_UART0
++              bool "Broadcom BCM270X UART0 (PL011)"
++              depends on ARCH_BCM2708 || ARCH_BCM2709
++              help
++                Say Y here if you want the debug print routines to direct
++                their output to UART 0. The port must have been initialised
++                by the boot-loader before use.
++
+ endchoice
+ config DEBUG_EXYNOS_UART
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -159,6 +159,8 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x003080
+ # Machine directory name.  This list is sorted alphanumerically
+ # by CONFIG_* macro name.
++machine-$(CONFIG_ARCH_BCM2708)                += bcm2708
++machine-$(CONFIG_ARCH_BCM2709)                += bcm2709
+ machine-$(CONFIG_ARCH_ALPINE)         += alpine
+ machine-$(CONFIG_ARCH_AT91)           += at91
+ machine-$(CONFIG_ARCH_AXXIA)          += axxia
+--- a/arch/arm/kernel/head.S
++++ b/arch/arm/kernel/head.S
+@@ -700,6 +700,14 @@ ARM_BE8(rev16     ip, ip)
+       ldrcc   r7, [r4], #4    @ use branch for delay slot
+       bcc     1b
+       ret     lr
++      nop
++      nop
++      nop
++      nop
++      nop
++      nop
++      nop
++      nop
+ #endif
+ ENDPROC(__fixup_a_pv_table)
+--- a/arch/arm/kernel/process.c
++++ b/arch/arm/kernel/process.c
+@@ -91,6 +91,16 @@ void arch_cpu_idle_exit(void)
+       ledtrig_cpu(CPU_LED_IDLE_END);
+ }
++char bcm2708_reboot_mode = 'h';
++
++int __init reboot_setup(char *str)
++{
++      bcm2708_reboot_mode = str[0];
++      return 1;
++}
++
++__setup("reboot=", reboot_setup);
++
+ void __show_regs(struct pt_regs *regs)
+ {
+       unsigned long flags;
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/Kconfig
+@@ -0,0 +1,23 @@
++menu "Broadcom BCM2708 Implementations"
++      depends on ARCH_BCM2708
++
++config MACH_BCM2708
++      bool "Broadcom BCM2708 Development Platform"
++      select NEED_MACH_MEMORY_H
++      select NEED_MACH_IO_H
++      select CPU_V6
++      select USE_OF
++      select ARCH_REQUIRE_GPIOLIB
++      select PINCTRL
++      select PINCTRL_BCM2835
++      help
++        Include support for the Broadcom(R) BCM2708 platform.
++
++config BCM2708_NOL2CACHE
++      bool "Videocore L2 cache disable"
++      depends on MACH_BCM2708
++        default n
++        help
++          Do not allow ARM to use GPU's L2 cache. Requires disable_l2cache in config.txt.
++
++endmenu
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-$(CONFIG_MACH_BCM2708)    += bcm2708.o
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/Makefile.boot
+@@ -0,0 +1,3 @@
++   zreladdr-y := 0x00008000
++params_phys-y := 0x00000100
++initrd_phys-y := 0x00800000
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/bcm2708.c
+@@ -0,0 +1,231 @@
++/*
++ *  linux/arch/arm/mach-bcm2708/bcm2708.c
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * 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
++ */
++
++#include <linux/init.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <asm/system_info.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++
++#include <mach/system.h>
++
++#include <linux/broadcom/vc_cma.h>
++
++/* Effectively we have an IOMMU (ARM<->VideoCore map) that is set up to
++ * give us IO access only to 64Mbytes of physical memory (26 bits).  We could
++ * represent this window by setting our dmamasks to 26 bits but, in fact
++ * we're not going to use addresses outside this range (they're not in real
++ * memory) so we don't bother.
++ *
++ * In the future we might include code to use this IOMMU to remap other
++ * physical addresses onto VideoCore memory then the use of 32-bits would be
++ * more legitimate.
++ */
++
++/* command line parameters */
++static unsigned boardrev, serial;
++static unsigned reboot_part = 0;
++
++static struct map_desc bcm2708_io_desc[] __initdata = {
++      {
++       .virtual = IO_ADDRESS(ARMCTRL_BASE),
++       .pfn = __phys_to_pfn(ARMCTRL_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(UART0_BASE),
++       .pfn = __phys_to_pfn(UART0_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(UART1_BASE),
++       .pfn = __phys_to_pfn(UART1_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(DMA_BASE),
++       .pfn = __phys_to_pfn(DMA_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(MCORE_BASE),
++       .pfn = __phys_to_pfn(MCORE_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(ST_BASE),
++       .pfn = __phys_to_pfn(ST_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(USB_BASE),
++       .pfn = __phys_to_pfn(USB_BASE),
++       .length = SZ_128K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(PM_BASE),
++       .pfn = __phys_to_pfn(PM_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(GPIO_BASE),
++       .pfn = __phys_to_pfn(GPIO_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE}
++};
++
++void __init bcm2708_map_io(void)
++{
++      iotable_init(bcm2708_io_desc, ARRAY_SIZE(bcm2708_io_desc));
++}
++
++int calc_rsts(int partition)
++{
++      return PM_PASSWORD |
++              ((partition & (1 << 0))  << 0) |
++              ((partition & (1 << 1))  << 1) |
++              ((partition & (1 << 2))  << 2) |
++              ((partition & (1 << 3))  << 3) |
++              ((partition & (1 << 4))  << 4) |
++              ((partition & (1 << 5))  << 5);
++}
++
++static void bcm2708_restart(enum reboot_mode mode, const char *cmd)
++{
++      extern char bcm2708_reboot_mode;
++      uint32_t pm_rstc, pm_wdog;
++      uint32_t timeout = 10;
++      uint32_t pm_rsts = 0;
++
++      if(bcm2708_reboot_mode == 'q')
++      {
++              // NOOBS < 1.3 booting with reboot=q
++              pm_rsts = readl(__io_address(PM_RSTS));
++              pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRQ_SET;
++      }
++      else if(bcm2708_reboot_mode == 'p')
++      {
++              // NOOBS < 1.3 halting
++              pm_rsts = readl(__io_address(PM_RSTS));
++              pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRH_SET;
++      }
++      else
++      {
++              pm_rsts = calc_rsts(reboot_part);
++      }
++
++      writel(pm_rsts, __io_address(PM_RSTS));
++
++      /* Setup watchdog for reset */
++      pm_rstc = readl(__io_address(PM_RSTC));
++
++      pm_wdog = PM_PASSWORD | (timeout & PM_WDOG_TIME_SET); // watchdog timer = timer clock / 16; need password (31:16) + value (11:0)
++      pm_rstc = PM_PASSWORD | (pm_rstc & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET;
++
++      writel(pm_wdog, __io_address(PM_WDOG));
++      writel(pm_rstc, __io_address(PM_RSTC));
++}
++
++/* We can't really power off, but if we do the normal reset scheme, and indicate to bootcode.bin not to reboot, then most of the chip will be powered off */
++static void bcm2708_power_off(void)
++{
++      extern char bcm2708_reboot_mode;
++      if(bcm2708_reboot_mode == 'q')
++      {
++              // NOOBS < v1.3
++              bcm2708_restart('p', "");
++      }
++      else
++      {
++              /* partition 63 is special code for HALT the bootloader knows not to boot*/
++              reboot_part = 63;
++              /* continue with normal reset mechanism */
++              bcm2708_restart(0, "");
++      }
++}
++
++static void __init bcm2708_init_uart1(void)
++{
++      struct device_node *np;
++
++      np = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-aux-uart");
++      if (of_device_is_available(np)) {
++              pr_info("bcm2708: Mini UART enabled\n");
++              writel(1, __io_address(UART1_BASE + 0x4));
++      }
++}
++
++void __init bcm2708_init(void)
++{
++      int ret;
++
++      vc_cma_early_init();
++
++      pm_power_off = bcm2708_power_off;
++
++      ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
++                                 NULL);
++      if (ret) {
++              pr_err("of_platform_populate failed: %d\n", ret);
++              BUG();
++      }
++
++      bcm2708_init_uart1();
++
++      system_rev = boardrev;
++      system_serial_low = serial;
++}
++
++void __init bcm2708_init_early(void)
++{
++      /*
++       * Some devices allocate their coherent buffers from atomic
++       * context. Increase size of atomic coherent pool to make sure such
++       * the allocations won't fail.
++       */
++      init_dma_coherent_pool_size(SZ_4M);
++}
++
++static void __init board_reserve(void)
++{
++      vc_cma_reserve();
++}
++
++static const char * const bcm2708_compat[] = {
++      "brcm,bcm2708",
++      NULL
++};
++
++MACHINE_START(BCM2708, "BCM2708")
++    /* Maintainer: Broadcom Europe Ltd. */
++      .map_io = bcm2708_map_io,
++      .init_machine = bcm2708_init,
++      .init_early = bcm2708_init_early,
++      .reserve = board_reserve,
++      .restart        = bcm2708_restart,
++      .dt_compat = bcm2708_compat,
++MACHINE_END
++
++module_param(boardrev, uint, 0644);
++module_param(serial, uint, 0644);
++module_param(reboot_part, uint, 0644);
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/debug-macro.S
+@@ -0,0 +1,22 @@
++/* arch/arm/mach-bcm2708/include/mach/debug-macro.S
++ *
++ * Debugging macro include header
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 1994-1999 Russell King
++ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++*/
++
++#include <mach/platform.h>
++
++              .macro  addruart, rp, rv, tmp
++              ldr     \rp, =UART0_BASE
++              ldr     \rv, =IO_ADDRESS(UART0_BASE)
++              .endm
++
++#include <debug/pl01x.S>
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/io.h
+@@ -0,0 +1,27 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/io.h
++ *
++ *  Copyright (C) 2003 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++#define __io(a)               __typesafe_io(a)
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/memory.h
+@@ -0,0 +1,57 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/memory.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_MEMORY_H
++#define __ASM_ARCH_MEMORY_H
++
++/* Memory overview:
++
++   [ARMcore] <--virtual addr-->
++   [ARMmmu] <--physical addr-->
++   [GERTmap] <--bus add-->
++   [VCperiph]
++
++*/
++
++/*
++ * Physical DRAM offset.
++ */
++#define BCM_PLAT_PHYS_OFFSET  UL(0x00000000)
++#define VC_ARMMEM_OFFSET      UL(0x00000000)   /* offset in VC of ARM memory */
++
++#ifdef CONFIG_BCM2708_NOL2CACHE
++ #define _REAL_BUS_OFFSET UL(0xC0000000)   /* don't use L1 or L2 caches */
++#else
++ #define _REAL_BUS_OFFSET UL(0x40000000)   /* use L2 cache */
++#endif
++
++/* We're using the memory at 64M in the VideoCore for Linux - this adjustment
++ * will provide the offset into this area as well as setting the bits that
++ * stop the L1 and L2 cache from being used
++ *
++ * WARNING: this only works because the ARM is given memory at a fixed location
++ *          (ARMMEM_OFFSET)
++ */
++#define BUS_OFFSET          (VC_ARMMEM_OFFSET + _REAL_BUS_OFFSET)
++#define __virt_to_bus(x)    ((x) + (BUS_OFFSET - PAGE_OFFSET))
++#define __bus_to_virt(x)    ((x) - (BUS_OFFSET - PAGE_OFFSET))
++#define __pfn_to_bus(x)     (__pfn_to_phys(x) + (BUS_OFFSET - BCM_PLAT_PHYS_OFFSET))
++#define __bus_to_pfn(x)     __phys_to_pfn((x) - (BUS_OFFSET - BCM_PLAT_PHYS_OFFSET))
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/platform.h
+@@ -0,0 +1,112 @@
++/*
++ * arch/arm/mach-bcm2708/include/mach/platform.h
++ *
++ * Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _BCM2708_PLATFORM_H
++#define _BCM2708_PLATFORM_H
++
++
++/* macros to get at IO space when running virtually */
++#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
++
++#define __io_address(n)     IOMEM(IO_ADDRESS(n))
++
++
++/*
++ *  SDRAM
++ */
++#define BCM2708_SDRAM_BASE           0x00000000
++
++/*
++ *  Logic expansion modules
++ *
++ */
++
++
++/* ------------------------------------------------------------------------
++ *  BCM2708 ARMCTRL Registers
++ * ------------------------------------------------------------------------
++ */
++
++#define HW_REGISTER_RW(addr) (addr)
++#define HW_REGISTER_RO(addr) (addr)
++
++/*
++ * Definitions and addresses for the ARM CONTROL logic
++ * This file is manually generated.
++ */
++
++#define BCM2708_PERI_BASE        0x20000000
++#define IC0_BASE                 (BCM2708_PERI_BASE + 0x2000)
++#define ST_BASE                  (BCM2708_PERI_BASE + 0x3000)   /* System Timer */
++#define MPHI_BASE              (BCM2708_PERI_BASE + 0x6000)   /* Message -based Parallel Host Interface */
++#define DMA_BASE               (BCM2708_PERI_BASE + 0x7000)   /* DMA controller */
++#define ARM_BASE                 (BCM2708_PERI_BASE + 0xB000)  /* BCM2708 ARM control block */
++#define PM_BASE                        (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */
++#define PCM_CLOCK_BASE           (BCM2708_PERI_BASE + 0x101098) /* PCM Clock */
++#define RNG_BASE                 (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */
++#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO */
++#define UART0_BASE               (BCM2708_PERI_BASE + 0x201000)       /* Uart 0 */
++#define MMCI0_BASE               (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
++#define I2S_BASE                 (BCM2708_PERI_BASE + 0x203000) /* I2S */
++#define SPI0_BASE              (BCM2708_PERI_BASE + 0x204000) /* SPI0 */
++#define BSC0_BASE              (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */
++#define UART1_BASE               (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
++#define EMMC_BASE                (BCM2708_PERI_BASE + 0x300000) /* eMMC interface */
++#define SMI_BASE               (BCM2708_PERI_BASE + 0x600000) /* SMI */
++#define BSC1_BASE              (BCM2708_PERI_BASE + 0x804000) /* BSC1 I2C/TWI */
++#define USB_BASE                 (BCM2708_PERI_BASE + 0x980000) /* DTC_OTG USB controller */
++#define MCORE_BASE               (BCM2708_PERI_BASE + 0x0000)   /* Fake frame buffer device (actually the multicore sync block*/
++
++#define ARMCTRL_BASE             (ARM_BASE + 0x000)
++#define ARMCTRL_IC_BASE          (ARM_BASE + 0x200)           /* ARM interrupt controller */
++#define ARMCTRL_TIMER0_1_BASE    (ARM_BASE + 0x400)           /* Timer 0 and 1 */
++#define ARMCTRL_0_SBM_BASE       (ARM_BASE + 0x800)           /* User 0 (ARM)'s Semaphores Doorbells and Mailboxes */
++
++/*
++ * Watchdog
++ */
++#define PM_RSTC                              (PM_BASE+0x1c)
++#define PM_RSTS                              (PM_BASE+0x20)
++#define PM_WDOG                              (PM_BASE+0x24)
++
++#define PM_WDOG_RESET                                         0000000000
++#define PM_PASSWORD                  0x5a000000
++#define PM_WDOG_TIME_SET             0x000fffff
++#define PM_RSTC_WRCFG_CLR              0xffffffcf
++#define PM_RSTC_WRCFG_SET              0x00000030
++#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
++#define PM_RSTC_RESET                  0x00000102
++
++#define PM_RSTS_HADPOR_SET                                 0x00001000
++#define PM_RSTS_HADSRH_SET                                 0x00000400
++#define PM_RSTS_HADSRF_SET                                 0x00000200
++#define PM_RSTS_HADSRQ_SET                                 0x00000100
++#define PM_RSTS_HADWRH_SET                                 0x00000040
++#define PM_RSTS_HADWRF_SET                                 0x00000020
++#define PM_RSTS_HADWRQ_SET                                 0x00000010
++#define PM_RSTS_HADDRH_SET                                 0x00000004
++#define PM_RSTS_HADDRF_SET                                 0x00000002
++#define PM_RSTS_HADDRQ_SET                                 0x00000001
++
++#define UART0_CLOCK      3000000
++
++#endif
++
++/* END */
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/system.h
+@@ -0,0 +1,37 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/system.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 2003 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_SYSTEM_H
++#define __ASM_ARCH_SYSTEM_H
++
++#include <linux/io.h>
++#include <mach/platform.h>
++
++static inline void arch_idle(void)
++{
++      /*
++       * This should do all the clock switching
++       * and wait for interrupt tricks
++       */
++      cpu_do_idle();
++}
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/uncompress.h
+@@ -0,0 +1,84 @@
++/*
++ *  arch/arm/mach-bcn2708/include/mach/uncompress.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 2003 ARM Limited
++ *
++ * 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
++ */
++
++#include <linux/io.h>
++#include <linux/amba/serial.h>
++#include <mach/platform.h>
++
++#define UART_BAUD 115200
++
++#define BCM2708_UART_DR   __io(UART0_BASE + UART01x_DR)
++#define BCM2708_UART_FR   __io(UART0_BASE + UART01x_FR)
++#define BCM2708_UART_IBRD __io(UART0_BASE + UART011_IBRD)
++#define BCM2708_UART_FBRD __io(UART0_BASE + UART011_FBRD)
++#define BCM2708_UART_LCRH __io(UART0_BASE + UART011_LCRH)
++#define BCM2708_UART_CR   __io(UART0_BASE + UART011_CR)
++
++/*
++ * This does not append a newline
++ */
++static inline void putc(int c)
++{
++      while (__raw_readl(BCM2708_UART_FR) & UART01x_FR_TXFF)
++              barrier();
++
++      __raw_writel(c, BCM2708_UART_DR);
++}
++
++static inline void flush(void)
++{
++      int fr;
++
++      do {
++              fr = __raw_readl(BCM2708_UART_FR);
++              barrier();
++      } while ((fr & (UART011_FR_TXFE | UART01x_FR_BUSY)) != UART011_FR_TXFE);
++}
++
++static inline void arch_decomp_setup(void)
++{
++      int temp, div, rem, frac;
++
++      temp = 16 * UART_BAUD;
++      div = UART0_CLOCK / temp;
++      rem = UART0_CLOCK % temp;
++      temp = (8 * rem) / UART_BAUD;
++      frac = (temp >> 1) + (temp & 1);
++
++      /* Make sure the UART is disabled before we start */
++      __raw_writel(0, BCM2708_UART_CR);
++
++      /* Set the baud rate */
++      __raw_writel(div, BCM2708_UART_IBRD);
++      __raw_writel(frac, BCM2708_UART_FBRD);
++
++      /* Set the UART to 8n1, FIFO enabled */
++      __raw_writel(UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN, BCM2708_UART_LCRH);
++
++      /* Enable the UART */
++      __raw_writel(UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_RXE,
++                      BCM2708_UART_CR);
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_wdog()
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/vmalloc.h
+@@ -0,0 +1,20 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/vmalloc.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * 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 VMALLOC_END           (0xe8000000)
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/Kconfig
+@@ -0,0 +1,16 @@
++menu "Broadcom BCM2709 Implementations"
++      depends on ARCH_BCM2709
++
++config MACH_BCM2709
++      bool "Broadcom BCM2709 Development Platform"
++      help
++        Include support for the Broadcom(R) BCM2709 platform.
++
++config BCM2708_NOL2CACHE
++      bool "Videocore L2 cache disable"
++      depends on MACH_BCM2709
++        default y
++        help
++          Do not allow ARM to use GPU's L2 cache. Requires disable_l2cache in config.txt.
++
++endmenu
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-$(CONFIG_MACH_BCM2709)    += bcm2709.o
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/Makefile.boot
+@@ -0,0 +1,3 @@
++   zreladdr-y := 0x00008000
++params_phys-y := 0x00000100
++initrd_phys-y := 0x00800000
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/bcm2709.c
+@@ -0,0 +1,380 @@
++/*
++ *  linux/arch/arm/mach-bcm2709/bcm2709.c
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * 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
++ */
++
++#include <linux/init.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/clk-provider.h>
++#include <linux/clocksource.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++
++#include <asm/system_info.h>
++#include <asm/mach-types.h>
++#include <asm/cputype.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++
++#include <mach/system.h>
++
++#include <linux/broadcom/vc_cma.h>
++
++/* Effectively we have an IOMMU (ARM<->VideoCore map) that is set up to
++ * give us IO access only to 64Mbytes of physical memory (26 bits).  We could
++ * represent this window by setting our dmamasks to 26 bits but, in fact
++ * we're not going to use addresses outside this range (they're not in real
++ * memory) so we don't bother.
++ *
++ * In the future we might include code to use this IOMMU to remap other
++ * physical addresses onto VideoCore memory then the use of 32-bits would be
++ * more legitimate.
++ */
++
++/* command line parameters */
++static unsigned boardrev, serial;
++static unsigned reboot_part = 0;
++
++static struct map_desc bcm2709_io_desc[] __initdata = {
++      {
++       .virtual = IO_ADDRESS(ARMCTRL_BASE),
++       .pfn = __phys_to_pfn(ARMCTRL_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(UART0_BASE),
++       .pfn = __phys_to_pfn(UART0_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(UART1_BASE),
++       .pfn = __phys_to_pfn(UART1_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(DMA_BASE),
++       .pfn = __phys_to_pfn(DMA_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(MCORE_BASE),
++       .pfn = __phys_to_pfn(MCORE_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(ST_BASE),
++       .pfn = __phys_to_pfn(ST_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(USB_BASE),
++       .pfn = __phys_to_pfn(USB_BASE),
++       .length = SZ_128K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(PM_BASE),
++       .pfn = __phys_to_pfn(PM_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(GPIO_BASE),
++       .pfn = __phys_to_pfn(GPIO_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++      {
++       .virtual = IO_ADDRESS(ARM_LOCAL_BASE),
++       .pfn = __phys_to_pfn(ARM_LOCAL_BASE),
++       .length = SZ_4K,
++       .type = MT_DEVICE},
++};
++
++void __init bcm2709_map_io(void)
++{
++      iotable_init(bcm2709_io_desc, ARRAY_SIZE(bcm2709_io_desc));
++}
++
++int calc_rsts(int partition)
++{
++      return PM_PASSWORD |
++              ((partition & (1 << 0))  << 0) |
++              ((partition & (1 << 1))  << 1) |
++              ((partition & (1 << 2))  << 2) |
++              ((partition & (1 << 3))  << 3) |
++              ((partition & (1 << 4))  << 4) |
++              ((partition & (1 << 5))  << 5);
++}
++
++static void bcm2709_restart(enum reboot_mode mode, const char *cmd)
++{
++      extern char bcm2708_reboot_mode;
++      uint32_t pm_rstc, pm_wdog;
++      uint32_t timeout = 10;
++      uint32_t pm_rsts = 0;
++
++      if(bcm2708_reboot_mode == 'q')
++      {
++              // NOOBS < 1.3 booting with reboot=q
++              pm_rsts = readl(__io_address(PM_RSTS));
++              pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRQ_SET;
++      }
++      else if(bcm2708_reboot_mode == 'p')
++      {
++              // NOOBS < 1.3 halting
++              pm_rsts = readl(__io_address(PM_RSTS));
++              pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRH_SET;
++      }
++      else
++      {
++              pm_rsts = calc_rsts(reboot_part);
++      }
++
++      writel(pm_rsts, __io_address(PM_RSTS));
++
++      /* Setup watchdog for reset */
++      pm_rstc = readl(__io_address(PM_RSTC));
++
++      pm_wdog = PM_PASSWORD | (timeout & PM_WDOG_TIME_SET); // watchdog timer = timer clock / 16; need password (31:16) + value (11:0)
++      pm_rstc = PM_PASSWORD | (pm_rstc & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET;
++
++      writel(pm_wdog, __io_address(PM_WDOG));
++      writel(pm_rstc, __io_address(PM_RSTC));
++}
++
++/* We can't really power off, but if we do the normal reset scheme, and indicate to bootcode.bin not to reboot, then most of the chip will be powered off */
++static void bcm2709_power_off(void)
++{
++      extern char bcm2708_reboot_mode;
++      if(bcm2708_reboot_mode == 'q')
++      {
++              // NOOBS < v1.3
++              bcm2709_restart('p', "");
++      }
++      else
++      {
++              /* partition 63 is special code for HALT the bootloader knows not to boot*/
++              reboot_part = 63;
++              /* continue with normal reset mechanism */
++              bcm2709_restart(0, "");
++      }
++}
++
++static void __init bcm2709_init_uart1(void)
++{
++      struct device_node *np;
++
++      np = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-aux-uart");
++      if (of_device_is_available(np)) {
++              pr_info("bcm2709: Mini UART enabled\n");
++              writel(1, __io_address(UART1_BASE + 0x4));
++      }
++}
++
++void __init bcm2709_init(void)
++{
++      int ret;
++
++      vc_cma_early_init();
++
++      pm_power_off = bcm2709_power_off;
++
++      ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
++                                 NULL);
++      if (ret) {
++              pr_err("of_platform_populate failed: %d\n", ret);
++              BUG();
++      }
++
++      bcm2709_init_uart1();
++
++      system_rev = boardrev;
++      system_serial_low = serial;
++}
++
++static void __init bcm2709_timer_init(void)
++{
++      // timer control
++      writel(0, __io_address(ARM_LOCAL_CONTROL));
++      // timer pre_scaler
++      writel(0x80000000, __io_address(ARM_LOCAL_PRESCALER)); // 19.2MHz
++      //writel(0x06AAAAAB, __io_address(ARM_LOCAL_PRESCALER)); // 1MHz
++
++      of_clk_init(NULL);
++      clocksource_probe();
++}
++
++
++void __init bcm2709_init_early(void)
++{
++      /*
++       * Some devices allocate their coherent buffers from atomic
++       * context. Increase size of atomic coherent pool to make sure such
++       * the allocations won't fail.
++       */
++      init_dma_coherent_pool_size(SZ_4M);
++}
++
++static void __init board_reserve(void)
++{
++      vc_cma_reserve();
++}
++
++
++#ifdef CONFIG_SMP
++#include <linux/smp.h>
++
++#include <asm/cacheflush.h>
++#include <asm/smp_plat.h>
++int dc4=0;
++//void dc4_log(unsigned x) { if (dc4) writel((x), __io_address(ST_BASE+10 + raw_smp_processor_id()*4)); }
++void dc4_log_dead(unsigned x) { if (dc4) writel((readl(__io_address(ST_BASE+0x10 + raw_smp_processor_id()*4)) & 0xffff) | ((x)<<16), __io_address(ST_BASE+0x10 + raw_smp_processor_id()*4)); }
++
++static void bcm2835_send_doorbell(const struct cpumask *mask, unsigned int irq)
++{
++        int cpu;
++        /*
++         * Ensure that stores to Normal memory are visible to the
++         * other CPUs before issuing the IPI.
++         */
++        dsb();
++
++        /* Convert our logical CPU mask into a physical one. */
++        for_each_cpu(cpu, mask)
++      {
++              /* submit softirq */
++              writel(1<<irq, __io_address(ARM_LOCAL_MAILBOX0_SET0 + 0x10 * MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0)));
++      }
++}
++
++void __init bcm2709_smp_init_cpus(void)
++{
++      void secondary_startup(void);
++      unsigned int i, ncores;
++
++      ncores = 4; // xxx scu_get_core_count(NULL);
++      printk("[%s] enter (%x->%x)\n", __FUNCTION__, (unsigned)virt_to_phys((void *)secondary_startup), (unsigned)__io_address(ST_BASE + 0x10));
++      printk("[%s] ncores=%d\n", __FUNCTION__, ncores);
++
++      for (i = 0; i < ncores; i++) {
++              set_cpu_possible(i, true);
++              /* enable IRQ (not FIQ) */
++              writel(0x1, __io_address(ARM_LOCAL_MAILBOX_INT_CONTROL0 + 0x4 * i));
++              //writel(0xf, __io_address(ARM_LOCAL_TIMER_INT_CONTROL0   + 0x4 * i));
++      }
++      set_smp_cross_call(bcm2835_send_doorbell);
++}
++
++/*
++ * for arch/arm/kernel/smp.c:smp_prepare_cpus(unsigned int max_cpus)
++ */
++void __init bcm2709_smp_prepare_cpus(unsigned int max_cpus)
++{
++    //void __iomem *scu_base;
++
++    printk("[%s] enter\n", __FUNCTION__);
++    //scu_base = scu_base_addr();
++    //scu_enable(scu_base);
++}
++
++/*
++ * for linux/arch/arm/kernel/smp.c:secondary_start_kernel(void)
++ */
++void __init bcm2709_secondary_init(unsigned int cpu)
++{
++    printk("[%s] enter cpu:%d\n", __FUNCTION__, cpu);
++    //gic_secondary_init(0);
++}
++
++/*
++ * for linux/arch/arm/kernel/smp.c:__cpu_up(..)
++ */
++int __init bcm2709_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++    void secondary_startup(void);
++    void *mbox_set = __io_address(ARM_LOCAL_MAILBOX3_SET0 + 0x10 * MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0));
++    void *mbox_clr = __io_address(ARM_LOCAL_MAILBOX3_CLR0 + 0x10 * MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0));
++    unsigned secondary_boot = (unsigned)virt_to_phys((void *)secondary_startup);
++    int timeout=20;
++    unsigned t = -1;
++    //printk("[%s] enter cpu:%d (%x->%p) %x\n", __FUNCTION__, cpu, secondary_boot, wake, readl(wake));
++
++    dsb();
++    BUG_ON(readl(mbox_clr) != 0);
++    writel(secondary_boot, mbox_set);
++
++    while (--timeout > 0) {
++      t = readl(mbox_clr);
++      if (t == 0) break;
++      cpu_relax();
++    }
++    if (timeout==0)
++        printk("[%s] cpu:%d failed to start (%x)\n", __FUNCTION__, cpu, t);
++    else
++        printk("[%s] cpu:%d started (%x) %d\n", __FUNCTION__, cpu, t, timeout);
++
++    return 0;
++}
++
++
++struct smp_operations  bcm2709_smp_ops __initdata = {
++      .smp_init_cpus          = bcm2709_smp_init_cpus,
++      .smp_prepare_cpus       = bcm2709_smp_prepare_cpus,
++      .smp_secondary_init     = bcm2709_secondary_init,
++      .smp_boot_secondary     = bcm2709_boot_secondary,
++};
++#endif
++
++static const char * const bcm2709_compat[] = {
++      "brcm,bcm2709",
++      "brcm,bcm2708", /* Could use bcm2708 in a pinch */
++      NULL
++};
++
++MACHINE_START(BCM2709, "BCM2709")
++    /* Maintainer: Broadcom Europe Ltd. */
++#ifdef CONFIG_SMP
++      .smp            = smp_ops(bcm2709_smp_ops),
++#endif
++      .map_io = bcm2709_map_io,
++      .init_time = bcm2709_timer_init,
++      .init_machine = bcm2709_init,
++      .init_early = bcm2709_init_early,
++      .reserve = board_reserve,
++      .restart        = bcm2709_restart,
++      .dt_compat = bcm2709_compat,
++MACHINE_END
++
++MACHINE_START(BCM2708, "BCM2709")
++    /* Maintainer: Broadcom Europe Ltd. */
++#ifdef CONFIG_SMP
++      .smp            = smp_ops(bcm2709_smp_ops),
++#endif
++      .map_io = bcm2709_map_io,
++      .init_time = bcm2709_timer_init,
++      .init_machine = bcm2709_init,
++      .init_early = bcm2709_init_early,
++      .reserve = board_reserve,
++      .restart        = bcm2709_restart,
++      .dt_compat = bcm2709_compat,
++MACHINE_END
++
++module_param(boardrev, uint, 0644);
++module_param(serial, uint, 0644);
++module_param(reboot_part, uint, 0644);
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/debug-macro.S
+@@ -0,0 +1,22 @@
++/* arch/arm/mach-bcm2708/include/mach/debug-macro.S
++ *
++ * Debugging macro include header
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 1994-1999 Russell King
++ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++*/
++
++#include <mach/platform.h>
++
++              .macro  addruart, rp, rv, tmp
++              ldr     \rp, =UART0_BASE
++              ldr     \rv, =IO_ADDRESS(UART0_BASE)
++              .endm
++
++#include <debug/pl01x.S>
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/entry-macro.S
+@@ -0,0 +1,123 @@
++/*
++ * arch/arm/mach-bcm2708/include/mach/entry-macro.S
++ *
++ * Low-level IRQ helper macros for BCM2708 platforms
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * 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
++ */
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++
++              .macro  disable_fiq
++              .endm
++
++              .macro  get_irqnr_preamble, base, tmp
++              ldr     \base, =IO_ADDRESS(ARMCTRL_IC_BASE)
++              .endm
++
++              .macro  arch_ret_to_user, tmp1, tmp2
++              .endm
++
++              .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
++              /* get core number */
++              mrc     p15, 0, \tmp, c0, c0, 5
++              ubfx    \tmp, \tmp, #0, #2
++
++              /* get core's local interrupt controller */
++              ldr     \irqstat, = __io_address(ARM_LOCAL_IRQ_PENDING0)        @ local interrupt source
++              add     \irqstat, \irqstat, \tmp, lsl #2
++              ldr     \tmp, [\irqstat]
++              /* ignore gpu interrupt */
++              bic     \tmp, #0x100
++              /* ignore mailbox interrupts */
++              bics    \tmp, #0xf0
++              beq     1005f
++
++              @ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
++              @ N.B. CLZ is an ARM5 instruction.
++              mov     \irqnr, #(ARM_IRQ_LOCAL_BASE + 31)
++              sub     \irqstat, \tmp, #1
++              eor     \irqstat, \irqstat, \tmp
++              clz     \tmp, \irqstat
++              sub     \irqnr, \tmp
++              b       1020f
++1005:
++              /* get core number */
++              mrc     p15, 0, \tmp, c0, c0, 5
++              ubfx    \tmp, \tmp, #0, #2
++
++                cmp   \tmp, #1
++              beq     1020f
++                cmp   \tmp, #2
++              beq     1020f
++                cmp   \tmp, #3
++              beq     1020f
++
++              /* get masked status */
++              ldr     \irqstat, [\base, #(ARM_IRQ_PEND0 - ARMCTRL_IC_BASE)]
++              mov     \irqnr, #(ARM_IRQ0_BASE + 31)
++              and     \tmp, \irqstat, #0x300           @ save bits 8 and 9
++              /* clear bits 8 and 9, and test */
++              bics    \irqstat, \irqstat, #0x300
++              bne     1010f
++
++              tst     \tmp, #0x100
++              ldrne   \irqstat, [\base, #(ARM_IRQ_PEND1 - ARMCTRL_IC_BASE)]
++              movne \irqnr, #(ARM_IRQ1_BASE + 31)
++              @ Mask out the interrupts also present in PEND0 - see SW-5809
++              bicne \irqstat, #((1<<7) | (1<<9) | (1<<10))
++              bicne \irqstat, #((1<<18) | (1<<19))
++              bne     1010f
++
++              tst     \tmp, #0x200
++              ldrne \irqstat, [\base, #(ARM_IRQ_PEND2 - ARMCTRL_IC_BASE)]
++              movne \irqnr, #(ARM_IRQ2_BASE + 31)
++              @ Mask out the interrupts also present in PEND0 - see SW-5809
++              bicne \irqstat, #((1<<21) | (1<<22) | (1<<23) | (1<<24) | (1<<25))
++              bicne \irqstat, #((1<<30))
++              beq 1020f
++
++1010:
++              @ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
++              @ N.B. CLZ is an ARM5 instruction.
++              sub     \tmp, \irqstat, #1
++              eor     \irqstat, \irqstat, \tmp
++              clz     \tmp, \irqstat
++              sub     \irqnr, \tmp
++
++1020: @ EQ will be set if no irqs pending
++
++              .endm
++
++              .macro  test_for_ipi, irqnr, irqstat, base, tmp
++              /* get core number */
++              mrc     p15, 0, \tmp, c0, c0, 5
++              ubfx    \tmp, \tmp, #0, #2
++              /* get core's mailbox interrupt control */
++              ldr     \irqstat, = __io_address(ARM_LOCAL_MAILBOX0_CLR0)       @ mbox_clr
++              add     \irqstat, \irqstat, \tmp, lsl #4
++              ldr     \tmp, [\irqstat]
++              cmp     \tmp, #0
++              beq     1030f
++              clz     \tmp, \tmp
++              rsb     \irqnr, \tmp, #31
++              mov     \tmp, #1
++              lsl     \tmp, \irqnr
++              str     \tmp, [\irqstat]  @ clear interrupt source
++              dsb
++1030: @ EQ will be set if no irqs pending
++              .endm
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/io.h
+@@ -0,0 +1,27 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/io.h
++ *
++ *  Copyright (C) 2003 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++#define __io(a)               __typesafe_io(a)
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/memory.h
+@@ -0,0 +1,57 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/memory.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_MEMORY_H
++#define __ASM_ARCH_MEMORY_H
++
++/* Memory overview:
++
++   [ARMcore] <--virtual addr-->
++   [ARMmmu] <--physical addr-->
++   [GERTmap] <--bus add-->
++   [VCperiph]
++
++*/
++
++/*
++ * Physical DRAM offset.
++ */
++#define BCM_PLAT_PHYS_OFFSET  UL(0x00000000)
++#define VC_ARMMEM_OFFSET      UL(0x00000000)   /* offset in VC of ARM memory */
++
++#ifdef CONFIG_BCM2708_NOL2CACHE
++ #define _REAL_BUS_OFFSET UL(0xC0000000)   /* don't use L1 or L2 caches */
++#else
++ #define _REAL_BUS_OFFSET UL(0x40000000)   /* use L2 cache */
++#endif
++
++/* We're using the memory at 64M in the VideoCore for Linux - this adjustment
++ * will provide the offset into this area as well as setting the bits that
++ * stop the L1 and L2 cache from being used
++ *
++ * WARNING: this only works because the ARM is given memory at a fixed location
++ *          (ARMMEM_OFFSET)
++ */
++#define BUS_OFFSET          (VC_ARMMEM_OFFSET + _REAL_BUS_OFFSET)
++#define __virt_to_bus(x)    ((x) + (BUS_OFFSET - PAGE_OFFSET))
++#define __bus_to_virt(x)    ((x) - (BUS_OFFSET - PAGE_OFFSET))
++#define __pfn_to_bus(x)     (__pfn_to_phys(x) + (BUS_OFFSET - BCM_PLAT_PHYS_OFFSET))
++#define __bus_to_pfn(x)     __phys_to_pfn((x) - (BUS_OFFSET - BCM_PLAT_PHYS_OFFSET))
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/platform.h
+@@ -0,0 +1,188 @@
++/*
++ * arch/arm/mach-bcm2708/include/mach/platform.h
++ *
++ * Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _BCM2708_PLATFORM_H
++#define _BCM2708_PLATFORM_H
++
++
++/* macros to get at IO space when running virtually */
++#define IO_ADDRESS(x) (((x) & 0x00ffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
++
++#define __io_address(n)     IOMEM(IO_ADDRESS(n))
++
++
++/*
++ *  SDRAM
++ */
++#define BCM2708_SDRAM_BASE           0x00000000
++
++/*
++ *  Logic expansion modules
++ *
++ */
++
++
++/* ------------------------------------------------------------------------
++ *  BCM2708 ARMCTRL Registers
++ * ------------------------------------------------------------------------
++ */
++
++#define HW_REGISTER_RW(addr) (addr)
++#define HW_REGISTER_RO(addr) (addr)
++
++/*
++ * Definitions and addresses for the ARM CONTROL logic
++ * This file is manually generated.
++ */
++
++#define BCM2708_PERI_BASE        0x3F000000
++#define IC0_BASE                 (BCM2708_PERI_BASE + 0x2000)
++#define ST_BASE                  (BCM2708_PERI_BASE + 0x3000)   /* System Timer */
++#define MPHI_BASE              (BCM2708_PERI_BASE + 0x6000)   /* Message -based Parallel Host Interface */
++#define DMA_BASE               (BCM2708_PERI_BASE + 0x7000)   /* DMA controller */
++#define ARM_BASE                 (BCM2708_PERI_BASE + 0xB000)  /* BCM2708 ARM control block */
++#define PM_BASE                        (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */
++#define PCM_CLOCK_BASE           (BCM2708_PERI_BASE + 0x101098) /* PCM Clock */
++#define RNG_BASE                 (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */
++#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO */
++#define UART0_BASE               (BCM2708_PERI_BASE + 0x201000)       /* Uart 0 */
++#define MMCI0_BASE               (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
++#define I2S_BASE                 (BCM2708_PERI_BASE + 0x203000) /* I2S */
++#define SPI0_BASE              (BCM2708_PERI_BASE + 0x204000) /* SPI0 */
++#define BSC0_BASE              (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */
++#define UART1_BASE               (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
++#define EMMC_BASE                (BCM2708_PERI_BASE + 0x300000) /* eMMC interface */
++#define SMI_BASE               (BCM2708_PERI_BASE + 0x600000) /* SMI */
++#define BSC1_BASE              (BCM2708_PERI_BASE + 0x804000) /* BSC1 I2C/TWI */
++#define USB_BASE                 (BCM2708_PERI_BASE + 0x980000) /* DTC_OTG USB controller */
++#define MCORE_BASE               (BCM2708_PERI_BASE + 0x0000)   /* Fake frame buffer device (actually the multicore sync block*/
++
++#define ARMCTRL_BASE             (ARM_BASE + 0x000)
++#define ARMCTRL_IC_BASE          (ARM_BASE + 0x200)           /* ARM interrupt controller */
++#define ARMCTRL_TIMER0_1_BASE    (ARM_BASE + 0x400)           /* Timer 0 and 1 */
++#define ARMCTRL_0_SBM_BASE       (ARM_BASE + 0x800)           /* User 0 (ARM)'s Semaphores Doorbells and Mailboxes */
++
++/*
++ * Watchdog
++ */
++#define PM_RSTC                              (PM_BASE+0x1c)
++#define PM_RSTS                              (PM_BASE+0x20)
++#define PM_WDOG                              (PM_BASE+0x24)
++
++#define PM_WDOG_RESET                                         0000000000
++#define PM_PASSWORD                  0x5a000000
++#define PM_WDOG_TIME_SET             0x000fffff
++#define PM_RSTC_WRCFG_CLR              0xffffffcf
++#define PM_RSTC_WRCFG_SET              0x00000030
++#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
++#define PM_RSTC_RESET                  0x00000102
++
++#define PM_RSTS_HADPOR_SET                                 0x00001000
++#define PM_RSTS_HADSRH_SET                                 0x00000400
++#define PM_RSTS_HADSRF_SET                                 0x00000200
++#define PM_RSTS_HADSRQ_SET                                 0x00000100
++#define PM_RSTS_HADWRH_SET                                 0x00000040
++#define PM_RSTS_HADWRF_SET                                 0x00000020
++#define PM_RSTS_HADWRQ_SET                                 0x00000010
++#define PM_RSTS_HADDRH_SET                                 0x00000004
++#define PM_RSTS_HADDRF_SET                                 0x00000002
++#define PM_RSTS_HADDRQ_SET                                 0x00000001
++
++#define UART0_CLOCK      3000000
++
++#define ARM_LOCAL_BASE 0x40000000
++#define ARM_LOCAL_CONTROL             HW_REGISTER_RW(ARM_LOCAL_BASE+0x000)
++
++#define ARM_LOCAL_CONTROL             HW_REGISTER_RW(ARM_LOCAL_BASE+0x000)
++#define ARM_LOCAL_PRESCALER           HW_REGISTER_RW(ARM_LOCAL_BASE+0x008)
++#define ARM_LOCAL_GPU_INT_ROUTING     HW_REGISTER_RW(ARM_LOCAL_BASE+0x00C)
++#define ARM_LOCAL_PM_ROUTING_SET      HW_REGISTER_RW(ARM_LOCAL_BASE+0x010)
++#define ARM_LOCAL_PM_ROUTING_CLR      HW_REGISTER_RW(ARM_LOCAL_BASE+0x014)
++#define ARM_LOCAL_TIMER_LS            HW_REGISTER_RW(ARM_LOCAL_BASE+0x01C)
++#define ARM_LOCAL_TIMER_MS            HW_REGISTER_RW(ARM_LOCAL_BASE+0x020)
++#define ARM_LOCAL_INT_ROUTING         HW_REGISTER_RW(ARM_LOCAL_BASE+0x024)
++#define ARM_LOCAL_AXI_COUNT           HW_REGISTER_RW(ARM_LOCAL_BASE+0x02C)
++#define ARM_LOCAL_AXI_IRQ             HW_REGISTER_RW(ARM_LOCAL_BASE+0x030)
++#define ARM_LOCAL_TIMER_CONTROL               HW_REGISTER_RW(ARM_LOCAL_BASE+0x034)
++#define ARM_LOCAL_TIMER_WRITE         HW_REGISTER_RW(ARM_LOCAL_BASE+0x038)
++
++#define ARM_LOCAL_TIMER_INT_CONTROL0  HW_REGISTER_RW(ARM_LOCAL_BASE+0x040)
++#define ARM_LOCAL_TIMER_INT_CONTROL1  HW_REGISTER_RW(ARM_LOCAL_BASE+0x044)
++#define ARM_LOCAL_TIMER_INT_CONTROL2  HW_REGISTER_RW(ARM_LOCAL_BASE+0x048)
++#define ARM_LOCAL_TIMER_INT_CONTROL3  HW_REGISTER_RW(ARM_LOCAL_BASE+0x04C)
++
++#define ARM_LOCAL_MAILBOX_INT_CONTROL0        HW_REGISTER_RW(ARM_LOCAL_BASE+0x050)
++#define ARM_LOCAL_MAILBOX_INT_CONTROL1        HW_REGISTER_RW(ARM_LOCAL_BASE+0x054)
++#define ARM_LOCAL_MAILBOX_INT_CONTROL2        HW_REGISTER_RW(ARM_LOCAL_BASE+0x058)
++#define ARM_LOCAL_MAILBOX_INT_CONTROL3        HW_REGISTER_RW(ARM_LOCAL_BASE+0x05C)
++
++#define ARM_LOCAL_IRQ_PENDING0                HW_REGISTER_RW(ARM_LOCAL_BASE+0x060)
++#define ARM_LOCAL_IRQ_PENDING1                HW_REGISTER_RW(ARM_LOCAL_BASE+0x064)
++#define ARM_LOCAL_IRQ_PENDING2                HW_REGISTER_RW(ARM_LOCAL_BASE+0x068)
++#define ARM_LOCAL_IRQ_PENDING3                HW_REGISTER_RW(ARM_LOCAL_BASE+0x06C)
++
++#define ARM_LOCAL_FIQ_PENDING0                HW_REGISTER_RW(ARM_LOCAL_BASE+0x070)
++#define ARM_LOCAL_FIQ_PENDING1                HW_REGISTER_RW(ARM_LOCAL_BASE+0x074)
++#define ARM_LOCAL_FIQ_PENDING2                HW_REGISTER_RW(ARM_LOCAL_BASE+0x078)
++#define ARM_LOCAL_FIQ_PENDING3                HW_REGISTER_RW(ARM_LOCAL_BASE+0x07C)
++
++#define ARM_LOCAL_MAILBOX0_SET0               HW_REGISTER_RW(ARM_LOCAL_BASE+0x080)
++#define ARM_LOCAL_MAILBOX1_SET0               HW_REGISTER_RW(ARM_LOCAL_BASE+0x084)
++#define ARM_LOCAL_MAILBOX2_SET0               HW_REGISTER_RW(ARM_LOCAL_BASE+0x088)
++#define ARM_LOCAL_MAILBOX3_SET0               HW_REGISTER_RW(ARM_LOCAL_BASE+0x08C)
++
++#define ARM_LOCAL_MAILBOX0_SET1               HW_REGISTER_RW(ARM_LOCAL_BASE+0x090)
++#define ARM_LOCAL_MAILBOX1_SET1               HW_REGISTER_RW(ARM_LOCAL_BASE+0x094)
++#define ARM_LOCAL_MAILBOX2_SET1               HW_REGISTER_RW(ARM_LOCAL_BASE+0x098)
++#define ARM_LOCAL_MAILBOX3_SET1               HW_REGISTER_RW(ARM_LOCAL_BASE+0x09C)
++
++#define ARM_LOCAL_MAILBOX0_SET2               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0A0)
++#define ARM_LOCAL_MAILBOX1_SET2               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0A4)
++#define ARM_LOCAL_MAILBOX2_SET2               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0A8)
++#define ARM_LOCAL_MAILBOX3_SET2               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0AC)
++
++#define ARM_LOCAL_MAILBOX0_SET3               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0B0)
++#define ARM_LOCAL_MAILBOX1_SET3               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0B4)
++#define ARM_LOCAL_MAILBOX2_SET3               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0B8)
++#define ARM_LOCAL_MAILBOX3_SET3               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0BC)
++
++#define ARM_LOCAL_MAILBOX0_CLR0               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0C0)
++#define ARM_LOCAL_MAILBOX1_CLR0               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0C4)
++#define ARM_LOCAL_MAILBOX2_CLR0               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0C8)
++#define ARM_LOCAL_MAILBOX3_CLR0               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0CC)
++
++#define ARM_LOCAL_MAILBOX0_CLR1               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0D0)
++#define ARM_LOCAL_MAILBOX1_CLR1               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0D4)
++#define ARM_LOCAL_MAILBOX2_CLR1               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0D8)
++#define ARM_LOCAL_MAILBOX3_CLR1               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0DC)
++
++#define ARM_LOCAL_MAILBOX0_CLR2               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0E0)
++#define ARM_LOCAL_MAILBOX1_CLR2               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0E4)
++#define ARM_LOCAL_MAILBOX2_CLR2               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0E8)
++#define ARM_LOCAL_MAILBOX3_CLR2               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0EC)
++
++#define ARM_LOCAL_MAILBOX0_CLR3               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0F0)
++#define ARM_LOCAL_MAILBOX1_CLR3               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0F4)
++#define ARM_LOCAL_MAILBOX2_CLR3               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0F8)
++#define ARM_LOCAL_MAILBOX3_CLR3               HW_REGISTER_RW(ARM_LOCAL_BASE+0x0FC)
++
++#endif
++
++/* END */
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/system.h
+@@ -0,0 +1,37 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/system.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 2003 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_SYSTEM_H
++#define __ASM_ARCH_SYSTEM_H
++
++#include <linux/io.h>
++#include <mach/platform.h>
++
++static inline void arch_idle(void)
++{
++      /*
++       * This should do all the clock switching
++       * and wait for interrupt tricks
++       */
++      cpu_do_idle();
++}
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/uncompress.h
+@@ -0,0 +1,84 @@
++/*
++ *  arch/arm/mach-bcn2708/include/mach/uncompress.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 2003 ARM Limited
++ *
++ * 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
++ */
++
++#include <linux/io.h>
++#include <linux/amba/serial.h>
++#include <mach/platform.h>
++
++#define UART_BAUD 115200
++
++#define BCM2708_UART_DR   __io(UART0_BASE + UART01x_DR)
++#define BCM2708_UART_FR   __io(UART0_BASE + UART01x_FR)
++#define BCM2708_UART_IBRD __io(UART0_BASE + UART011_IBRD)
++#define BCM2708_UART_FBRD __io(UART0_BASE + UART011_FBRD)
++#define BCM2708_UART_LCRH __io(UART0_BASE + UART011_LCRH)
++#define BCM2708_UART_CR   __io(UART0_BASE + UART011_CR)
++
++/*
++ * This does not append a newline
++ */
++static inline void putc(int c)
++{
++      while (__raw_readl(BCM2708_UART_FR) & UART01x_FR_TXFF)
++              barrier();
++
++      __raw_writel(c, BCM2708_UART_DR);
++}
++
++static inline void flush(void)
++{
++      int fr;
++
++      do {
++              fr = __raw_readl(BCM2708_UART_FR);
++              barrier();
++      } while ((fr & (UART011_FR_TXFE | UART01x_FR_BUSY)) != UART011_FR_TXFE);
++}
++
++static inline void arch_decomp_setup(void)
++{
++      int temp, div, rem, frac;
++
++      temp = 16 * UART_BAUD;
++      div = UART0_CLOCK / temp;
++      rem = UART0_CLOCK % temp;
++      temp = (8 * rem) / UART_BAUD;
++      frac = (temp >> 1) + (temp & 1);
++
++      /* Make sure the UART is disabled before we start */
++      __raw_writel(0, BCM2708_UART_CR);
++
++      /* Set the baud rate */
++      __raw_writel(div, BCM2708_UART_IBRD);
++      __raw_writel(frac, BCM2708_UART_FBRD);
++
++      /* Set the UART to 8n1, FIFO enabled */
++      __raw_writel(UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN, BCM2708_UART_LCRH);
++
++      /* Enable the UART */
++      __raw_writel(UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_RXE,
++                      BCM2708_UART_CR);
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_wdog()
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/vc_mem.h
+@@ -0,0 +1,35 @@
++/*****************************************************************************
++* Copyright 2010 - 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( VC_MEM_H )
++#define VC_MEM_H
++
++#include <linux/ioctl.h>
++
++#define VC_MEM_IOC_MAGIC  'v'
++
++#define VC_MEM_IOC_MEM_PHYS_ADDR    _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
++#define VC_MEM_IOC_MEM_SIZE         _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
++#define VC_MEM_IOC_MEM_BASE         _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
++#define VC_MEM_IOC_MEM_LOAD         _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
++
++#if defined( __KERNEL__ )
++#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
++
++extern unsigned long mm_vc_mem_phys_addr;
++extern unsigned int  mm_vc_mem_size;
++extern int vc_mem_get_current_size( void );
++#endif
++
++#endif  /* VC_MEM_H */
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/vmalloc.h
+@@ -0,0 +1,20 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/vmalloc.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * 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 VMALLOC_END           (0xff000000)
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/vc_mem.c
+@@ -0,0 +1,431 @@
++/*****************************************************************************
++* Copyright 2010 - 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 <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/cdev.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <asm/uaccess.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_data/mailbox-bcm2708.h>
++
++#ifdef CONFIG_ARCH_KONA
++#include <chal/chal_ipc.h>
++#elif defined(CONFIG_ARCH_BCM2708) || defined(CONFIG_ARCH_BCM2709)
++#else
++#include <csp/chal_ipc.h>
++#endif
++
++#include "mach/vc_mem.h"
++
++#define DRIVER_NAME  "vc-mem"
++
++// Device (/dev) related variables
++static dev_t vc_mem_devnum = 0;
++static struct class *vc_mem_class = NULL;
++static struct cdev vc_mem_cdev;
++static int vc_mem_inited = 0;
++
++#ifdef CONFIG_DEBUG_FS
++static struct dentry *vc_mem_debugfs_entry;
++#endif
++
++/*
++ * Videocore memory addresses and size
++ *
++ * Drivers that wish to know the videocore memory addresses and sizes should
++ * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
++ * headers. This allows the other drivers to not be tied down to a a certain
++ * address/size at compile time.
++ *
++ * In the future, the goal is to have the videocore memory virtual address and
++ * size be calculated at boot time rather than at compile time. The decision of
++ * where the videocore memory resides and its size would be in the hands of the
++ * bootloader (and/or kernel). When that happens, the values of these variables
++ * would be calculated and assigned in the init function.
++ */
++// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
++unsigned long mm_vc_mem_phys_addr = 0x00000000;
++unsigned int mm_vc_mem_size = 0;
++unsigned int mm_vc_mem_base = 0;
++
++EXPORT_SYMBOL(mm_vc_mem_phys_addr);
++EXPORT_SYMBOL(mm_vc_mem_size);
++EXPORT_SYMBOL(mm_vc_mem_base);
++
++static uint phys_addr = 0;
++static uint mem_size = 0;
++static uint mem_base = 0;
++
++
++/****************************************************************************
++*
++*   vc_mem_open
++*
++***************************************************************************/
++
++static int
++vc_mem_open(struct inode *inode, struct file *file)
++{
++      (void) inode;
++      (void) file;
++
++      pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++      return 0;
++}
++
++/****************************************************************************
++*
++*   vc_mem_release
++*
++***************************************************************************/
++
++static int
++vc_mem_release(struct inode *inode, struct file *file)
++{
++      (void) inode;
++      (void) file;
++
++      pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++      return 0;
++}
++
++/****************************************************************************
++*
++*   vc_mem_get_size
++*
++***************************************************************************/
++
++static void
++vc_mem_get_size(void)
++{
++}
++
++/****************************************************************************
++*
++*   vc_mem_get_base
++*
++***************************************************************************/
++
++static void
++vc_mem_get_base(void)
++{
++}
++
++/****************************************************************************
++*
++*   vc_mem_get_current_size
++*
++***************************************************************************/
++
++int
++vc_mem_get_current_size(void)
++{
++      return mm_vc_mem_size;
++}
++
++EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
++
++/****************************************************************************
++*
++*   vc_mem_ioctl
++*
++***************************************************************************/
++
++static long
++vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++      int rc = 0;
++
++      (void) cmd;
++      (void) arg;
++
++      pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++      switch (cmd) {
++      case VC_MEM_IOC_MEM_PHYS_ADDR:
++              {
++                      pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
++                              __func__, (void *) mm_vc_mem_phys_addr);
++
++                      if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
++                                       sizeof (mm_vc_mem_phys_addr)) != 0) {
++                              rc = -EFAULT;
++                      }
++                      break;
++              }
++      case VC_MEM_IOC_MEM_SIZE:
++              {
++                      // Get the videocore memory size first
++                      vc_mem_get_size();
++
++                      pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
++                              mm_vc_mem_size);
++
++                      if (copy_to_user((void *) arg, &mm_vc_mem_size,
++                                       sizeof (mm_vc_mem_size)) != 0) {
++                              rc = -EFAULT;
++                      }
++                      break;
++              }
++      case VC_MEM_IOC_MEM_BASE:
++              {
++                      // Get the videocore memory base
++                      vc_mem_get_base();
++
++                      pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
++                              mm_vc_mem_base);
++
++                      if (copy_to_user((void *) arg, &mm_vc_mem_base,
++                                       sizeof (mm_vc_mem_base)) != 0) {
++                              rc = -EFAULT;
++                      }
++                      break;
++              }
++      case VC_MEM_IOC_MEM_LOAD:
++              {
++                      // Get the videocore memory base
++                      vc_mem_get_base();
++
++                      pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
++                              mm_vc_mem_base);
++
++                      if (copy_to_user((void *) arg, &mm_vc_mem_base,
++                                       sizeof (mm_vc_mem_base)) != 0) {
++                              rc = -EFAULT;
++                      }
++                      break;
++              }
++      default:
++              {
++                      return -ENOTTY;
++              }
++      }
++      pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
++
++      return rc;
++}
++
++/****************************************************************************
++*
++*   vc_mem_mmap
++*
++***************************************************************************/
++
++static int
++vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++      int rc = 0;
++      unsigned long length = vma->vm_end - vma->vm_start;
++      unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
++
++      pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
++              __func__, (long) vma->vm_start, (long) vma->vm_end,
++              (long) vma->vm_pgoff);
++
++      if (offset + length > mm_vc_mem_size) {
++              pr_err("%s: length %ld is too big\n", __func__, length);
++              return -EINVAL;
++      }
++      // Do not cache the memory map
++      vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++      rc = remap_pfn_range(vma, vma->vm_start,
++                           (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
++                           vma->vm_pgoff, length, vma->vm_page_prot);
++      if (rc != 0) {
++              pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
++      }
++
++      return rc;
++}
++
++/****************************************************************************
++*
++*   File Operations for the driver.
++*
++***************************************************************************/
++
++static const struct file_operations vc_mem_fops = {
++      .owner = THIS_MODULE,
++      .open = vc_mem_open,
++      .release = vc_mem_release,
++      .unlocked_ioctl = vc_mem_ioctl,
++      .mmap = vc_mem_mmap,
++};
++
++#ifdef CONFIG_DEBUG_FS
++static void vc_mem_debugfs_deinit(void)
++{
++      debugfs_remove_recursive(vc_mem_debugfs_entry);
++      vc_mem_debugfs_entry = NULL;
++}
++
++
++static int vc_mem_debugfs_init(
++      struct device *dev)
++{
++      vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
++      if (!vc_mem_debugfs_entry) {
++              dev_warn(dev, "could not create debugfs entry\n");
++              return -EFAULT;
++      }
++
++      if (!debugfs_create_x32("vc_mem_phys_addr",
++                              0444,
++                              vc_mem_debugfs_entry,
++                              (u32 *)&mm_vc_mem_phys_addr)) {
++              dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
++                      __func__);
++              goto fail;
++      }
++
++      if (!debugfs_create_x32("vc_mem_size",
++                              0444,
++                              vc_mem_debugfs_entry,
++                              (u32 *)&mm_vc_mem_size)) {
++              dev_warn(dev, "%s:could not create vc_mem_size entry\n",
++                      __func__);
++              goto fail;
++      }
++
++      if (!debugfs_create_x32("vc_mem_base",
++                              0444,
++                              vc_mem_debugfs_entry,
++                              (u32 *)&mm_vc_mem_base)) {
++              dev_warn(dev, "%s:could not create vc_mem_base entry\n",
++                       __func__);
++              goto fail;
++      }
++
++      return 0;
++
++fail:
++      vc_mem_debugfs_deinit();
++      return -EFAULT;
++}
++
++#endif /* CONFIG_DEBUG_FS */
++
++
++/****************************************************************************
++*
++*   vc_mem_init
++*
++***************************************************************************/
++
++static int __init
++vc_mem_init(void)
++{
++      int rc = -EFAULT;
++      struct device *dev;
++
++      pr_debug("%s: called\n", __func__);
++
++      mm_vc_mem_phys_addr = phys_addr;
++      mm_vc_mem_size = mem_size;
++      mm_vc_mem_base = mem_base;
++
++      vc_mem_get_size();
++
++      pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
++              mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
++
++      if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
++              pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
++                     __func__, rc);
++              goto out_err;
++      }
++
++      cdev_init(&vc_mem_cdev, &vc_mem_fops);
++      if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
++              pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
++              goto out_unregister;
++      }
++
++      vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
++      if (IS_ERR(vc_mem_class)) {
++              rc = PTR_ERR(vc_mem_class);
++              pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
++              goto out_cdev_del;
++      }
++
++      dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
++                          DRIVER_NAME);
++      if (IS_ERR(dev)) {
++              rc = PTR_ERR(dev);
++              pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
++              goto out_class_destroy;
++      }
++
++#ifdef CONFIG_DEBUG_FS
++      /* don't fail if the debug entries cannot be created */
++      vc_mem_debugfs_init(dev);
++#endif
++
++      vc_mem_inited = 1;
++      return 0;
++
++      device_destroy(vc_mem_class, vc_mem_devnum);
++
++      out_class_destroy:
++      class_destroy(vc_mem_class);
++      vc_mem_class = NULL;
++
++      out_cdev_del:
++      cdev_del(&vc_mem_cdev);
++
++      out_unregister:
++      unregister_chrdev_region(vc_mem_devnum, 1);
++
++      out_err:
++      return -1;
++}
++
++/****************************************************************************
++*
++*   vc_mem_exit
++*
++***************************************************************************/
++
++static void __exit
++vc_mem_exit(void)
++{
++      pr_debug("%s: called\n", __func__);
++
++      if (vc_mem_inited) {
++#if CONFIG_DEBUG_FS
++              vc_mem_debugfs_deinit();
++#endif
++              device_destroy(vc_mem_class, vc_mem_devnum);
++              class_destroy(vc_mem_class);
++              cdev_del(&vc_mem_cdev);
++              unregister_chrdev_region(vc_mem_devnum, 1);
++      }
++}
++
++module_init(vc_mem_init);
++module_exit(vc_mem_exit);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Broadcom Corporation");
++
++module_param(phys_addr, uint, 0644);
++module_param(mem_size, uint, 0644);
++module_param(mem_base, uint, 0644);
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -358,7 +358,7 @@ config CPU_PJ4B
+ # ARMv6
+ config CPU_V6
+-      bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
++      bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX || MACH_BCM2708)
+       select CPU_32v6
+       select CPU_ABRT_EV6
+       select CPU_CACHE_V6
+--- a/arch/arm/mm/proc-v6.S
++++ b/arch/arm/mm/proc-v6.S
+@@ -73,10 +73,19 @@ ENDPROC(cpu_v6_reset)
+  *
+  *    IRQs are already disabled.
+  */
++
++/* See jira SW-5991 for details of this workaround */
+ ENTRY(cpu_v6_do_idle)
+-      mov     r1, #0
+-      mcr     p15, 0, r1, c7, c10, 4          @ DWB - WFI may enter a low-power mode
+-      mcr     p15, 0, r1, c7, c0, 4           @ wait for interrupt
++      .align 5
++      mov     r1, #2
++1:    subs    r1, #1
++      nop
++      mcreq   p15, 0, r1, c7, c10, 4          @ DWB - WFI may enter a low-power mode
++      mcreq   p15, 0, r1, c7, c0, 4           @ wait for interrupt
++      nop
++      nop
++      nop
++      bne 1b
+       ret     lr
+ ENTRY(cpu_v6_dcache_clean_area)
+--- a/arch/arm/mm/proc-v7.S
++++ b/arch/arm/mm/proc-v7.S
+@@ -480,6 +480,7 @@ __errata_finish:
+       orr     r0, r0, r6                      @ set them
+  THUMB(       orr     r0, r0, #1 << 30        )       @ Thumb exceptions
+       ret     lr                              @ return to head.S:__ret
++        .space 256
+ ENDPROC(__v7_setup)
+       .align  2
+--- a/arch/arm/tools/mach-types
++++ b/arch/arm/tools/mach-types
+@@ -522,6 +522,8 @@ torbreck           MACH_TORBRECK           TORBRECK                3090
+ prima2_evb            MACH_PRIMA2_EVB         PRIMA2_EVB              3103
+ paz00                 MACH_PAZ00              PAZ00                   3128
+ acmenetusfoxg20               MACH_ACMENETUSFOXG20    ACMENETUSFOXG20         3129
++bcm2708                       MACH_BCM2708            BCM2708                 3138
++bcm2709                       MACH_BCM2709            BCM2709                 3139
+ 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
+--- a/drivers/clocksource/Makefile
++++ b/drivers/clocksource/Makefile
+@@ -19,7 +19,7 @@ obj-$(CONFIG_CLKSRC_NOMADIK_MTU)     += noma
+ obj-$(CONFIG_CLKSRC_DBX500_PRCMU)     += clksrc-dbx500-prcmu.o
+ obj-$(CONFIG_ARMADA_370_XP_TIMER)     += time-armada-370-xp.o
+ obj-$(CONFIG_ORION_TIMER)     += time-orion.o
+-obj-$(CONFIG_ARCH_BCM2835)    += bcm2835_timer.o
++obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)      += bcm2835_timer.o
+ obj-$(CONFIG_ARCH_CLPS711X)   += clps711x-timer.o
+ obj-$(CONFIG_ARCH_ATLAS7)     += timer-atlas7.o
+ obj-$(CONFIG_ARCH_MOXART)     += moxart_timer.o
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -2,6 +2,9 @@ obj-$(CONFIG_IRQCHIP)                  += irqchip.o
+ obj-$(CONFIG_ARCH_BCM2835)            += irq-bcm2835.o
+ obj-$(CONFIG_ARCH_BCM2835)            += irq-bcm2836.o
++obj-$(CONFIG_ARCH_BCM2708)            += irq-bcm2835.o
++obj-$(CONFIG_ARCH_BCM2709)            += irq-bcm2835.o
++obj-$(CONFIG_ARCH_BCM2709)            += irq-bcm2836.o
+ obj-$(CONFIG_ARCH_EXYNOS)             += exynos-combiner.o
+ obj-$(CONFIG_ARCH_HIP04)              += irq-hip04.o
+ obj-$(CONFIG_ARCH_MMP)                        += irq-mmp.o
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -289,6 +289,7 @@ struct mmc_host {
+ #define MMC_CAP2_HSX00_1_2V   (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
+ #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
+ #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)   /* No physical write protect pin, assume that card is always read-write */
++#define MMC_CAP2_FORCE_MULTIBLOCK (1 << 31)   /* Always use multiblock transfers */
+       mmc_pm_flag_t           pm_caps;        /* supported pm features */
diff --git a/target/linux/brcm2708/patches-4.4/0028-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch b/target/linux/brcm2708/patches-4.4/0028-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch
new file mode 100644 (file)
index 0000000..53fc545
--- /dev/null
@@ -0,0 +1,138 @@
+From ceefa4e6b0d4b529eed6666120674cccde24d59a Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 11 Nov 2015 21:01:15 +0000
+Subject: [PATCH 028/127] squash: include ARCH_BCM2708 / ARCH_BCM2709
+
+---
+ drivers/char/hw_random/Kconfig    |  2 +-
+ drivers/mailbox/Kconfig           |  2 +-
+ drivers/mailbox/bcm2835-mailbox.c | 18 ++++++++++++++++--
+ drivers/pinctrl/Makefile          |  1 +
+ drivers/pwm/Kconfig               |  2 +-
+ drivers/spi/Kconfig               |  2 +-
+ drivers/watchdog/Kconfig          |  2 +-
+ sound/soc/bcm/Kconfig             |  2 +-
+ 8 files changed, 23 insertions(+), 8 deletions(-)
+
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -90,7 +90,7 @@ config HW_RANDOM_BCM63XX
+ config HW_RANDOM_BCM2835
+       tristate "Broadcom BCM2835 Random Number Generator support"
+-      depends on ARCH_BCM2835
++      depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+       default HW_RANDOM
+       ---help---
+         This driver provides kernel-side support for the Random Number
+--- a/drivers/mailbox/Kconfig
++++ b/drivers/mailbox/Kconfig
+@@ -65,7 +65,7 @@ config ALTERA_MBOX
+ config BCM2835_MBOX
+       tristate "BCM2835 Mailbox"
+-      depends on ARCH_BCM2835
++      depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+       help
+         An implementation of the BCM2385 Mailbox.  It is used to invoke
+         the services of the Videocore. Say Y here if you want to use the
+--- a/drivers/mailbox/bcm2835-mailbox.c
++++ b/drivers/mailbox/bcm2835-mailbox.c
+@@ -51,12 +51,15 @@
+ #define MAIL1_WRT     (ARM_0_MAIL1 + 0x00)
+ #define MAIL1_STA     (ARM_0_MAIL1 + 0x18)
++/* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
++#ifndef ARM_MS_FULL
+ /* Status register: FIFO state. */
+ #define ARM_MS_FULL           BIT(31)
+ #define ARM_MS_EMPTY          BIT(30)
+ /* Configuration register: Enable interrupts. */
+ #define ARM_MC_IHAVEDATAIRQEN BIT(0)
++#endif
+ struct bcm2835_mbox {
+       void __iomem *regs;
+@@ -151,7 +154,7 @@ static int bcm2835_mbox_probe(struct pla
+               return -ENOMEM;
+       spin_lock_init(&mbox->lock);
+-      ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
++      ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
+                              bcm2835_mbox_irq, 0, dev_name(dev), mbox);
+       if (ret) {
+               dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
+@@ -209,7 +212,18 @@ static struct platform_driver bcm2835_mb
+       .probe          = bcm2835_mbox_probe,
+       .remove         = bcm2835_mbox_remove,
+ };
+-module_platform_driver(bcm2835_mbox_driver);
++
++static int __init bcm2835_mbox_init(void)
++{
++      return platform_driver_register(&bcm2835_mbox_driver);
++}
++arch_initcall(bcm2835_mbox_init);
++
++static void __init bcm2835_mbox_exit(void)
++{
++      platform_driver_unregister(&bcm2835_mbox_driver);
++}
++module_exit(bcm2835_mbox_exit);
+ MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+ MODULE_DESCRIPTION("BCM2835 mailbox IPC driver");
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -40,6 +40,7 @@ obj-$(CONFIG_PINCTRL_TB10X)  += pinctrl-t
+ obj-$(CONFIG_PINCTRL_ST)      += pinctrl-st.o
+ obj-$(CONFIG_PINCTRL_ZYNQ)    += pinctrl-zynq.o
++obj-$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += bcm/
+ obj-$(CONFIG_ARCH_BCM)                += bcm/
+ obj-$(CONFIG_ARCH_BERLIN)     += berlin/
+ obj-y                         += freescale/
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -85,7 +85,7 @@ config PWM_BCM_KONA
+ config PWM_BCM2835
+       tristate "BCM2835 PWM support"
+-      depends on ARCH_BCM2835
++      depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+       help
+         PWM framework driver for BCM2835 controller (Raspberry Pi)
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -78,7 +78,7 @@ config SPI_ATMEL
+ config SPI_BCM2835
+       tristate "BCM2835 SPI controller"
+       depends on GPIOLIB
+-      depends on ARCH_BCM2835 || COMPILE_TEST
++      depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST
+       depends on GPIOLIB
+       help
+         This selects a driver for the Broadcom BCM2835 SPI master.
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -1291,7 +1291,7 @@ config BCM63XX_WDT
+ config BCM2835_WDT
+       tristate "Broadcom BCM2835 hardware watchdog"
+-      depends on ARCH_BCM2835
++      depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+       select WATCHDOG_CORE
+       help
+         Watchdog driver for the built in watchdog hardware in Broadcom
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -1,6 +1,6 @@
+ config SND_BCM2835_SOC_I2S
+       tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
+-      depends on ARCH_BCM2835 || COMPILE_TEST
++      depends on ARCH_BCM2835 || MACH_BCM2708 || MACH_BCM2709 || COMPILE_TEST
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       select REGMAP_MMIO
+       help
diff --git a/target/linux/brcm2708/patches-4.4/0029-Add-dwc_otg-driver.patch b/target/linux/brcm2708/patches-4.4/0029-Add-dwc_otg-driver.patch
new file mode 100644 (file)
index 0000000..ee8c4fa
--- /dev/null
@@ -0,0 +1,60780 @@
+From 3fa74ccc327ddeb8f718cf4c42d61b43cc0a9626 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 1 May 2013 19:46:17 +0100
+Subject: [PATCH 029/127] Add dwc_otg driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+usb: dwc: fix lockdep false positive
+
+Signed-off-by: Kari Suvanto <karis79@gmail.com>
+
+usb: dwc: fix inconsistent lock state
+
+Signed-off-by: Kari Suvanto <karis79@gmail.com>
+
+Add FIQ patch to dwc_otg driver. Enable with dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance.
+Thanks to Gordon and Costas
+
+Avoid dynamic memory allocation for channel lock in USB driver. Thanks ddv2005.
+
+Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh
+
+Make sure we wait for the reset to finish
+
+dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent kernel
+        memory corruption, escalating to OOPS under high USB load.
+
+dwc_otg: Fix unsafe access of QTD during URB enqueue
+
+In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the
+transaction could complete almost immediately after the qtd was assigned
+to a host channel during URB enqueue, which meant the qtd pointer was no
+longer valid having been completed and removed. Usually, this resulted in
+an OOPS during URB submission. By predetermining whether transactions
+need to be queued or not, this unsafe pointer access is avoided.
+
+This bug was only evident on the Pi model A where a device was attached
+that had no periodic endpoints (e.g. USB pendrive or some wlan devices).
+
+dwc_otg: Fix incorrect URB allocation error handling
+
+If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS
+because for some reason a member of the *unallocated* struct was set to
+zero. Error handling changed to fail correctly.
+
+dwc_otg: fix potential use-after-free case in interrupt handler
+
+If a transaction had previously aborted, certain interrupts are
+enabled to track error counts and reset where necessary. On IN
+endpoints the host generates an ACK interrupt near-simultaneously
+with completion of transfer. In the case where this transfer had
+previously had an error, this results in a use-after-free on
+the QTD memory space with a 1-byte length being overwritten to
+0x00.
+
+dwc_otg: add handling of SPLIT transaction data toggle errors
+
+Previously a data toggle error on packets from a USB1.1 device behind
+a TT would result in the Pi locking up as the driver never handled
+the associated interrupt. Patch adds basic retry mechanism and
+interrupt acknowledgement to cater for either a chance toggle error or
+for devices that have a broken initial toggle state (FT8U232/FT232BM).
+
+dwc_otg: implement tasklet for returning URBs to usbcore hcd layer
+
+The dwc_otg driver interrupt handler for transfer completion will spend
+a very long time with interrupts disabled when a URB is completed -
+this is because usb_hcd_giveback_urb is called from within the handler
+which for a USB device driver with complicated processing (e.g. webcam)
+will take an exorbitant amount of time to complete. This results in
+missed completion interrupts for other USB packets which lead to them
+being dropped due to microframe overruns.
+
+This patch splits returning the URB to the usb hcd layer into a
+high-priority tasklet. This will have most benefit for isochronous IN
+transfers but will also have incidental benefit where multiple periodic
+devices are active at once.
+
+dwc_otg: fix NAK holdoff and allow on split transactions only
+
+This corrects a bug where if a single active non-periodic endpoint
+had at least one transaction in its qh, on frnum == MAX_FRNUM the qh
+would get skipped and never get queued again. This would result in
+a silent device until error detection (automatic or otherwise) would
+either reset the device or flush and requeue the URBs.
+
+Additionally the NAK holdoff was enabled for all transactions - this
+would potentially stall a HS endpoint for 1ms if a previous error state
+enabled this interrupt and the next response was a NAK. Fix so that
+only split transactions get held off.
+
+dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock held in completion handler
+
+usb_hcd_unlink_urb_from_ep must be called with the HCD lock held.  Calling it
+asynchronously in the tasklet was not safe (regression in
+c4564d4a1a0a9b10d4419e48239f5d99e88d2667).
+
+This change unlinks it from the endpoint prior to queueing it for handling in
+the tasklet, and also adds a check to ensure the urb is OK to be unlinked
+before doing so.
+
+NULL pointer dereference kernel oopses had been observed in usb_hcd_giveback_urb
+when a USB device was unplugged/replugged during data transfer.  This effect
+was reproduced using automated USB port power control, hundreds of replug
+events were performed during active transfers to confirm that the problem was
+eliminated.
+
+USB fix using a FIQ to implement split transactions
+
+This commit adds a FIQ implementaion that schedules
+the split transactions using a FIQ so we don't get
+held off by the interrupt latency of Linux
+
+dwc_otg: fix device attributes and avoid kernel warnings on boot
+
+dcw_otg: avoid logging function that can cause panics
+
+See: https://github.com/raspberrypi/firmware/issues/21
+Thanks to cleverca22 for fix
+
+dwc_otg: mask correct interrupts after transaction error recovery
+
+The dwc_otg driver will unmask certain interrupts on a transaction
+that previously halted in the error state in order to reset the
+QTD error count. The various fine-grained interrupt handlers do not
+consider that other interrupts besides themselves were unmasked.
+
+By disabling the two other interrupts only ever enabled in DMA mode
+for this purpose, we can avoid unnecessary function calls in the
+IRQ handler. This will also prevent an unneccesary FIQ interrupt
+from being generated if the FIQ is enabled.
+
+dwc_otg: fiq: prevent FIQ thrash and incorrect state passing to IRQ
+
+In the case of a transaction to a device that had previously aborted
+due to an error, several interrupts are enabled to reset the error
+count when a device responds. This has the side-effect of making the
+FIQ thrash because the hardware will generate multiple instances of
+a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK
+on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the
+associated interrupts.
+
+Additionally, on non-split transactions make sure that only unmasked
+interrupts are cleared. This caused a hard-to-trigger but serious
+race condition when you had the combination of an endpoint awaiting
+error recovery and a transaction completed on an endpoint - due to
+the sequencing and timing of interrupts generated by the dwc_otg core,
+it was possible to confuse the IRQ handler.
+
+Fix function tracing
+
+dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue
+
+dwc_otg: prevent OOPSes during device disconnects
+
+The dwc_otg_urb_enqueue function is thread-unsafe. In particular the
+access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and
+friends does not occur within a critical section and so if a device
+was unplugged during activity there was a high chance that the
+usbcore hub_thread would try to disable the endpoint with partially-
+formed entries in the URB queue. This would result in BUG() or null
+pointer dereferences.
+
+Fix so that access of urb->hcpriv, enqueuing to the hardware and
+adding to usbcore endpoint URB lists is contained within a single
+critical section.
+
+dwc_otg: prevent BUG() in TT allocation if hub address is > 16
+
+A fixed-size array is used to track TT allocation. This was
+previously set to 16 which caused a crash because
+dwc_otg_hcd_allocate_port would read past the end of the array.
+
+This was hit if a hub was plugged in which enumerated as addr > 16,
+due to previous device resets or unplugs.
+
+Also add #ifdef FIQ_DEBUG around hcd->hub_port_alloc[], which grows
+to a large size if 128 hub addresses are supported. This field is
+for debug only for tracking which frame an allocate happened in.
+
+dwc_otg: make channel halts with unknown state less damaging
+
+If the IRQ received a channel halt interrupt through the FIQ
+with no other bits set, the IRQ would not release the host
+channel and never complete the URB.
+
+Add catchall handling to treat as a transaction error and retry.
+
+dwc_otg: fiq_split: use TTs with more granularity
+
+This fixes certain issues with split transaction scheduling.
+
+- Isochronous multi-packet OUT transactions now hog the TT until
+  they are completed - this prevents hubs aborting transactions
+  if they get a periodic start-split out-of-order
+- Don't perform TT allocation on non-periodic endpoints - this
+  allows simultaneous use of the TT's bulk/control and periodic
+  transaction buffers
+
+This commit will mainly affect USB audio playback.
+
+dwc_otg: fix potential sleep while atomic during urb enqueue
+
+Fixes a regression introduced with eb1b482a. Kmalloc called from
+dwc_otg_hcd_qtd_add / dwc_otg_hcd_qtd_create did not always have
+the GPF_ATOMIC flag set. Force this flag when inside the larger
+critical section.
+
+dwc_otg: make fiq_split_enable imply fiq_fix_enable
+
+Failing to set up the FIQ correctly would result in
+"IRQ 32: nobody cared" errors in dmesg.
+
+dwc_otg: prevent crashes on host port disconnects
+
+Fix several issues resulting in crashes or inconsistent state
+if a Model A root port was disconnected.
+
+- Clean up queue heads properly in kill_urbs_in_qh_list by
+  removing the empty QHs from the schedule lists
+- Set the halt status properly to prevent IRQ handlers from
+  using freed memory
+- Add fiq_split related cleanup for saved registers
+- Make microframe scheduling reclaim host channels if
+  active during a disconnect
+- Abort URBs with -ESHUTDOWN status response, informing
+  device drivers so they respond in a more correct fashion
+  and don't try to resubmit URBs
+- Prevent IRQ handlers from attempting to handle channel
+  interrupts if the associated URB was dequeued (and the
+  driver state was cleared)
+
+dwc_otg: prevent leaking URBs during enqueue
+
+A dwc_otg_urb would get leaked if the HCD enqueue function
+failed for any reason. Free the URB at the appropriate points.
+
+dwc_otg: Enable NAK holdoff for control split transactions
+
+Certain low-speed devices take a very long time to complete a
+data or status stage of a control transaction, producing NAK
+responses until they complete internal processing - the USB2.0
+spec limit is up to 500mS. This causes the same type of interrupt
+storm as seen with USB-serial dongles prior to c8edb238.
+
+In certain circumstances, usually while booting, this interrupt
+storm could cause SD card timeouts.
+
+dwc_otg: Fix for occasional lockup on boot when doing a USB reset
+
+dwc_otg: Don't issue traffic to LS devices in FS mode
+
+Issuing low-speed packets when the root port is in full-speed mode
+causes the root port to stop responding. Explicitly fail when
+enqueuing URBs to a LS endpoint on a FS bus.
+
+Fix ARM architecture issue with local_irq_restore()
+
+If local_fiq_enable() is called before a local_irq_restore(flags) where
+the flags variable has the F bit set, the FIQ will be erroneously disabled.
+
+Fixup arch_local_irq_restore to avoid trampling the F bit in CPSR.
+
+Also fix some of the hacks previously implemented for previous dwc_otg
+incarnations.
+
+dwc_otg: fiq_fsm: Base commit for driver rewrite
+
+This commit removes the previous FIQ fixes entirely and adds fiq_fsm.
+
+This rewrite features much more complete support for split transactions
+and takes into account several OTG hardware bugs. High-speed
+isochronous transactions are also capable of being performed by fiq_fsm.
+
+All driver options have been removed and replaced with:
+  - dwc_otg.fiq_enable (bool)
+  - dwc_otg.fiq_fsm_enable (bool)
+  - dwc_otg.fiq_fsm_mask (bitmask)
+  - dwc_otg.nak_holdoff (unsigned int)
+
+Defaults are specified such that fiq_fsm behaves similarly to the
+previously implemented FIQ fixes.
+
+fiq_fsm: Push error recovery into the FIQ when fiq_fsm is used
+
+If the transfer associated with a QTD failed due to a bus error, the HCD
+would retry the transfer up to 3 times (implementing the USB2.0
+three-strikes retry in software).
+
+Due to the masking mechanism used by fiq_fsm, it is only possible to pass
+a single interrupt through to the HCD per-transfer.
+
+In this instance host channels would fall off the radar because the error
+reset would function, but the subsequent channel halt would be lost.
+
+Push the error count reset into the FIQ handler.
+
+fiq_fsm: Implement timeout mechanism
+
+For full-speed endpoints with a large packet size, interrupt latency
+runs the risk of the FIQ starting a transaction too late in a full-speed
+frame. If the device is still transmitting data when EOF2 for the
+downstream frame occurs, the hub will disable the port. This change is
+not reflected in the hub status endpoint and the device becomes
+unresponsive.
+
+Prevent high-bandwidth transactions from being started too late in a
+frame. The mechanism is not guaranteed: a combination of bit stuffing
+and hub latency may still result in a device overrunning.
+
+fiq_fsm: fix bounce buffer utilisation for Isochronous OUT
+
+Multi-packet isochronous OUT transactions were subject to a few bounday
+bugs. Fix them.
+
+Audio playback is now much more robust: however, an issue stands with
+devices that have adaptive sinks - ALSA plays samples too fast.
+
+dwc_otg: Return full-speed frame numbers in HS mode
+
+The frame counter increments on every *microframe* in high-speed mode.
+Most device drivers expect this number to be in full-speed frames - this
+caused considerable confusion to e.g. snd_usb_audio which uses the
+frame counter to estimate the number of samples played.
+
+fiq_fsm: save PID on completion of interrupt OUT transfers
+
+Also add edge case handling for interrupt transports.
+
+Note that for periodic split IN, data toggles are unimplemented in the
+OTG host hardware - it unconditionally accepts any PID.
+
+fiq_fsm: add missing case for fiq_fsm_tt_in_use()
+
+Certain combinations of bitrate and endpoint activity could
+result in a periodic transaction erroneously getting started
+while the previous Isochronous OUT was still active.
+
+fiq_fsm: clear hcintmsk for aborted transactions
+
+Prevents the FIQ from erroneously handling interrupts
+on a timed out channel.
+
+fiq_fsm: enable by default
+
+fiq_fsm: fix dequeues for non-periodic split transactions
+
+If a dequeue happened between the SSPLIT and CSPLIT phases of the
+transaction, the HCD would never receive an interrupt.
+
+fiq_fsm: Disable by default
+
+fiq_fsm: Handle HC babble errors
+
+The HCTSIZ transfer size field raises a babble interrupt if
+the counter wraps. Handle the resulting interrupt in this case.
+
+dwc_otg: fix interrupt registration for fiq_enable=0
+
+Additionally make the module parameter conditional for wherever
+hcd->fiq_state is touched.
+
+fiq_fsm: Enable by default
+
+dwc_otg: Fix various issues with root port and transaction errors
+
+Process the host port interrupts correctly (and don't trample them).
+Root port hotplug now functional again.
+
+Fix a few thinkos with the transaction error passthrough for fiq_fsm.
+
+fiq_fsm: Implement hack for Split Interrupt transactions
+
+Hubs aren't too picky about which endpoint we send Control type split
+transactions to. By treating Interrupt transfers as Control, it is
+possible to use the non-periodic queue in the OTG core as well as the
+non-periodic FIFOs in the hub itself. This massively reduces the
+microframe exclusivity/contention that periodic split transactions
+otherwise have to enforce.
+
+It goes without saying that this is a fairly egregious USB specification
+violation, but it works.
+
+Original idea by Hans Petter Selasky @ FreeBSD.org.
+
+dwc_otg: FIQ support on SMP. Set up FIQ stack and handler on Core 0 only.
+
+dwc_otg: introduce fiq_fsm_spin(un|)lock()
+
+SMP safety for the FIQ relies on register read-modify write cycles being
+completed in the correct order. Several places in the DWC code modify
+registers also touched by the FIQ. Protect these by a bare-bones lock
+mechanism.
+
+This also makes it possible to run the FIQ and IRQ handlers on different
+cores.
+
+fiq_fsm: fix build on bcm2708 and bcm2709 platforms
+
+dwc_otg: put some barriers back where they should be for UP
+
+bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core active
+
+dwc_otg: fixup read-modify-write in critical paths
+
+Be more careful about read-modify-write on registers that the FIQ
+also touches.
+
+Guard fiq_fsm_spin_lock with fiq_enable check
+
+fiq_fsm: Falling out of the state machine isn't fatal
+
+This edge case can be hit if the port is disabled while the FIQ is
+in the middle of a transaction. Make the effects less severe.
+
+Also get rid of the useless return value.
+
+squash: dwc_otg: Allow to build without SMP
+
+usb: core: make overcurrent messages more prominent
+
+Hub overcurrent messages are more serious than "debug". Increase loglevel.
+
+usb: dwc_otg: Don't use dma_to_virt()
+
+Commit 6ce0d20 changes dma_to_virt() which breaks this driver.
+Open code the old dma_to_virt() implementation to work around this.
+
+Limit the use of __bus_to_virt() to cases where transfer_buffer_length
+is set and transfer_buffer is not set. This is done to increase the
+chance that this driver will also work on ARCH_BCM2835.
+
+transfer_buffer should not be NULL if the length is set, but the
+comment in the code indicates that there are situations where this
+might happen. drivers/usb/isp1760/isp1760-hcd.c also has a similar
+comment pointing to a possible: 'usb storage / SCSI bug'.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Fix crash when fiq_enable=0
+
+dwc_otg: fiq_fsm: Make high-speed isochronous strided transfers work properly
+
+Certain low-bandwidth high-speed USB devices (specialist audio devices,
+compressed-frame webcams) have packet intervals > 1 microframe.
+
+Stride these transfers in the FIQ by using the start-of-frame interrupt
+to restart the channel at the right time.
+
+dwc_otg: Force host mode to fix incorrect compute module boards
+
+dwc_otg: Add ARCH_BCM2835 support
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Simplify FIQ irq number code
+
+Dropping ATAGS means we can simplify the FIQ irq number code.
+Also add error checking on the returned irq number.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Remove duplicate gadget probe/unregister function
+---
+ arch/arm/include/asm/irqflags.h                    |   16 +-
+ arch/arm/kernel/fiqasm.S                           |    4 +
+ drivers/usb/Makefile                               |    1 +
+ drivers/usb/core/generic.c                         |    1 +
+ drivers/usb/core/hub.c                             |    2 +-
+ drivers/usb/core/message.c                         |   79 +
+ drivers/usb/core/otg_whitelist.h                   |  114 +-
+ drivers/usb/gadget/file_storage.c                  | 3676 ++++++++++
+ drivers/usb/host/Kconfig                           |   13 +
+ drivers/usb/host/Makefile                          |    2 +
+ drivers/usb/host/dwc_common_port/Makefile          |   58 +
+ drivers/usb/host/dwc_common_port/Makefile.fbsd     |   17 +
+ drivers/usb/host/dwc_common_port/Makefile.linux    |   49 +
+ drivers/usb/host/dwc_common_port/changes.txt       |  174 +
+ drivers/usb/host/dwc_common_port/doc/doxygen.cfg   |  270 +
+ drivers/usb/host/dwc_common_port/dwc_cc.c          |  532 ++
+ drivers/usb/host/dwc_common_port/dwc_cc.h          |  224 +
+ drivers/usb/host/dwc_common_port/dwc_common_fbsd.c | 1308 ++++
+ .../usb/host/dwc_common_port/dwc_common_linux.c    | 1433 ++++
+ drivers/usb/host/dwc_common_port/dwc_common_nbsd.c | 1275 ++++
+ drivers/usb/host/dwc_common_port/dwc_crypto.c      |  308 +
+ drivers/usb/host/dwc_common_port/dwc_crypto.h      |  111 +
+ drivers/usb/host/dwc_common_port/dwc_dh.c          |  291 +
+ drivers/usb/host/dwc_common_port/dwc_dh.h          |  106 +
+ drivers/usb/host/dwc_common_port/dwc_list.h        |  594 ++
+ drivers/usb/host/dwc_common_port/dwc_mem.c         |  245 +
+ drivers/usb/host/dwc_common_port/dwc_modpow.c      |  636 ++
+ drivers/usb/host/dwc_common_port/dwc_modpow.h      |   34 +
+ drivers/usb/host/dwc_common_port/dwc_notifier.c    |  319 +
+ drivers/usb/host/dwc_common_port/dwc_notifier.h    |  122 +
+ drivers/usb/host/dwc_common_port/dwc_os.h          | 1276 ++++
+ drivers/usb/host/dwc_common_port/usb.h             |  946 +++
+ drivers/usb/host/dwc_otg/Makefile                  |   82 +
+ drivers/usb/host/dwc_otg/doc/doxygen.cfg           |  224 +
+ drivers/usb/host/dwc_otg/dummy_audio.c             | 1575 +++++
+ drivers/usb/host/dwc_otg/dwc_cfi_common.h          |  142 +
+ drivers/usb/host/dwc_otg/dwc_otg_adp.c             |  854 +++
+ drivers/usb/host/dwc_otg/dwc_otg_adp.h             |   80 +
+ drivers/usb/host/dwc_otg/dwc_otg_attr.c            | 1210 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_attr.h            |   89 +
+ drivers/usb/host/dwc_otg/dwc_otg_cfi.c             | 1876 +++++
+ drivers/usb/host/dwc_otg/dwc_otg_cfi.h             |  320 +
+ drivers/usb/host/dwc_otg/dwc_otg_cil.c             | 7141 ++++++++++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_cil.h             | 1464 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c        | 1594 +++++
+ drivers/usb/host/dwc_otg/dwc_otg_core_if.h         |  705 ++
+ drivers/usb/host/dwc_otg/dwc_otg_dbg.h             |  117 +
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c          | 1757 +++++
+ drivers/usb/host/dwc_otg/dwc_otg_driver.h          |   86 +
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c         | 1355 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h         |  370 +
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S        |   80 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c             | 4257 ++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.h             |  862 +++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c        | 1132 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h          |  417 ++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c        | 2714 ++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c       | 1005 +++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c       |  957 +++
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h          |  188 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd.c             | 2712 ++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_pcd.h             |  266 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h          |  360 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c        | 5147 ++++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c       | 1280 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_regs.h            | 2550 +++++++
+ drivers/usb/host/dwc_otg/test/Makefile             |   16 +
+ drivers/usb/host/dwc_otg/test/dwc_otg_test.pm      |  337 +
+ drivers/usb/host/dwc_otg/test/test_mod_param.pl    |  133 +
+ drivers/usb/host/dwc_otg/test/test_sysfs.pl        |  193 +
+ 70 files changed, 59867 insertions(+), 16 deletions(-)
+ create mode 100644 drivers/usb/gadget/file_storage.c
+ create mode 100644 drivers/usb/host/dwc_common_port/Makefile
+ create mode 100644 drivers/usb/host/dwc_common_port/Makefile.fbsd
+ create mode 100644 drivers/usb/host/dwc_common_port/Makefile.linux
+ create mode 100644 drivers/usb/host/dwc_common_port/changes.txt
+ create mode 100644 drivers/usb/host/dwc_common_port/doc/doxygen.cfg
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_linux.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_list.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_mem.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_os.h
+ create mode 100644 drivers/usb/host/dwc_common_port/usb.h
+ create mode 100644 drivers/usb/host/dwc_otg/Makefile
+ create mode 100644 drivers/usb/host/dwc_otg/doc/doxygen.cfg
+ create mode 100644 drivers/usb/host/dwc_otg/dummy_audio.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_cfi_common.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_core_if.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_dbg.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h
+ create mode 100644 drivers/usb/host/dwc_otg/test/Makefile
+ create mode 100644 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
+ create mode 100644 drivers/usb/host/dwc_otg/test/test_mod_param.pl
+ create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl
+
+--- a/arch/arm/include/asm/irqflags.h
++++ b/arch/arm/include/asm/irqflags.h
+@@ -162,13 +162,23 @@ static inline unsigned long arch_local_s
+ }
+ /*
+- * restore saved IRQ & FIQ state
++ * restore saved IRQ state
+  */
+ #define arch_local_irq_restore arch_local_irq_restore
+ static inline void arch_local_irq_restore(unsigned long flags)
+ {
+-      asm volatile(
+-              "       msr     " IRQMASK_REG_NAME_W ", %0      @ local_irq_restore"
++      unsigned long temp = 0;
++      flags &= ~(1 << 6);
++      asm volatile (
++              " mrs %0, cpsr"
++              : "=r" (temp)
++              :
++              : "memory", "cc");
++              /* Preserve FIQ bit */
++              temp &= (1 << 6);
++              flags = flags | temp;
++      asm volatile (
++              "    msr    cpsr_c, %0    @ local_irq_restore"
+               :
+               : "r" (flags)
+               : "memory", "cc");
+--- a/arch/arm/kernel/fiqasm.S
++++ b/arch/arm/kernel/fiqasm.S
+@@ -47,3 +47,7 @@ ENTRY(__get_fiq_regs)
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       ret     lr
+ ENDPROC(__get_fiq_regs)
++
++ENTRY(__FIQ_Branch)
++      mov pc, r8
++ENDPROC(__FIQ_Branch)
+--- a/drivers/usb/Makefile
++++ b/drivers/usb/Makefile
+@@ -7,6 +7,7 @@
+ obj-$(CONFIG_USB)             += core/
+ obj-$(CONFIG_USB_SUPPORT)     += phy/
++obj-$(CONFIG_USB_DWCOTG)      += host/
+ obj-$(CONFIG_USB_DWC3)                += dwc3/
+ obj-$(CONFIG_USB_DWC2)                += dwc2/
+ obj-$(CONFIG_USB_ISP1760)     += isp1760/
+--- a/drivers/usb/core/generic.c
++++ b/drivers/usb/core/generic.c
+@@ -152,6 +152,7 @@ int usb_choose_configuration(struct usb_
+               dev_warn(&udev->dev,
+                       "no configuration chosen from %d choice%s\n",
+                       num_configs, plural(num_configs));
++              dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
+       }
+       return i;
+ }
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -4946,7 +4946,7 @@ static void port_event(struct usb_hub *h
+       if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+               u16 status = 0, unused;
+-              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 */
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -1909,6 +1909,85 @@ free_interfaces:
+       if (cp->string == NULL &&
+                       !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
+               cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
++/* Uncomment this define to enable the HS Electrical Test support */
++#define DWC_HS_ELECT_TST 1
++#ifdef DWC_HS_ELECT_TST
++              /* Here we implement the HS Electrical Test support. The
++               * tester uses a vendor ID of 0x1A0A to indicate we should
++               * run a special test sequence. The product ID tells us
++               * which sequence to run. We invoke the test sequence by
++               * sending a non-standard SetFeature command to our root
++               * hub port. Our dwc_otg_hcd_hub_control() routine will
++               * recognize the command and perform the desired test
++               * sequence.
++               */
++              if (dev->descriptor.idVendor == 0x1A0A) {
++                      /* HSOTG Electrical Test */
++                      dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
++
++                      if (dev->bus && dev->bus->root_hub) {
++                              struct usb_device *hdev = dev->bus->root_hub;
++                              dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
++
++                              switch (dev->descriptor.idProduct) {
++                              case 0x0101:    /* TEST_SE0_NAK */
++                                      dev_warn(&dev->dev, "TEST_SE0_NAK\n");
++                                      usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++                                                      USB_REQ_SET_FEATURE, USB_RT_PORT,
++                                                      USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
++                                      break;
++
++                              case 0x0102:    /* TEST_J */
++                                      dev_warn(&dev->dev, "TEST_J\n");
++                                      usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++                                                      USB_REQ_SET_FEATURE, USB_RT_PORT,
++                                                      USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
++                                      break;
++
++                              case 0x0103:    /* TEST_K */
++                                      dev_warn(&dev->dev, "TEST_K\n");
++                                      usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++                                                      USB_REQ_SET_FEATURE, USB_RT_PORT,
++                                                      USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
++                                      break;
++
++                              case 0x0104:    /* TEST_PACKET */
++                                      dev_warn(&dev->dev, "TEST_PACKET\n");
++                                      usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++                                                      USB_REQ_SET_FEATURE, USB_RT_PORT,
++                                                      USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
++                                      break;
++
++                              case 0x0105:    /* TEST_FORCE_ENABLE */
++                                      dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
++                                      usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++                                                      USB_REQ_SET_FEATURE, USB_RT_PORT,
++                                                      USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
++                                      break;
++
++                              case 0x0106:    /* HS_HOST_PORT_SUSPEND_RESUME */
++                                      dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
++                                      usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++                                                      USB_REQ_SET_FEATURE, USB_RT_PORT,
++                                                      USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
++                                      break;
++
++                              case 0x0107:    /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
++                                      dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
++                                      usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++                                                      USB_REQ_SET_FEATURE, USB_RT_PORT,
++                                                      USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
++                                      break;
++
++                              case 0x0108:    /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
++                                      dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
++                                      usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++                                                      USB_REQ_SET_FEATURE, USB_RT_PORT,
++                                                      USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
++                              }
++                      }
++              }
++#endif /* DWC_HS_ELECT_TST */
+       /* Now that the interfaces are installed, re-enable LPM. */
+       usb_unlocked_enable_lpm(dev);
+--- a/drivers/usb/core/otg_whitelist.h
++++ b/drivers/usb/core/otg_whitelist.h
+@@ -19,33 +19,82 @@
+ static struct usb_device_id whitelist_table[] = {
+ /* hubs are optional in OTG, but very handy ... */
++#define CERT_WITHOUT_HUBS
++#if defined(CERT_WITHOUT_HUBS)
++{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
++#else
+ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
+ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
++{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
++#endif
+ #ifdef        CONFIG_USB_PRINTER              /* ignoring nonstatic linkage! */
+ /* FIXME actually, printers are NOT supposed to use device classes;
+  * they're supposed to use interface classes...
+  */
+-{ USB_DEVICE_INFO(7, 1, 1) },
+-{ USB_DEVICE_INFO(7, 1, 2) },
+-{ USB_DEVICE_INFO(7, 1, 3) },
++//{ USB_DEVICE_INFO(7, 1, 1) },
++//{ USB_DEVICE_INFO(7, 1, 2) },
++//{ USB_DEVICE_INFO(7, 1, 3) },
+ #endif
+ #ifdef        CONFIG_USB_NET_CDCETHER
+ /* Linux-USB CDC Ethernet gadget */
+-{ USB_DEVICE(0x0525, 0xa4a1), },
++//{ USB_DEVICE(0x0525, 0xa4a1), },
+ /* Linux-USB CDC Ethernet + RNDIS gadget */
+-{ USB_DEVICE(0x0525, 0xa4a2), },
++//{ USB_DEVICE(0x0525, 0xa4a2), },
+ #endif
+ #if   defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
+ /* gadget zero, for testing */
+-{ USB_DEVICE(0x0525, 0xa4a0), },
++//{ USB_DEVICE(0x0525, 0xa4a0), },
+ #endif
++/* OPT Tester */
++{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
++{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
++{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
++{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
++{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
++{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME  */
++{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
++{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
++
++/* Sony cameras */
++{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
++
++/* Memory Devices */
++//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
++//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
++//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
++//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD  */
++{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
++//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
++
++/* HP Printers */
++//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
++//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
++
++/* Speakers */
++//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
++//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
++
+ { }   /* Terminating entry */
+ };
++static inline void report_errors(struct usb_device *dev)
++{
++      /* OTG MESSAGE: report errors here, customize to match your product */
++      dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
++               le16_to_cpu(dev->descriptor.idVendor),
++               le16_to_cpu(dev->descriptor.idProduct));
++        if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
++                dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
++        } else {
++                dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
++        }
++}
++
++
+ static int is_targeted(struct usb_device *dev)
+ {
+       struct usb_device_id    *id = whitelist_table;
+@@ -95,16 +144,57 @@ static int is_targeted(struct usb_device
+                       continue;
+               return 1;
+-      }
++              /* NOTE: can't use usb_match_id() since interface caches
++               * aren't set up yet. this is cut/paste from that code.
++               */
++              for (id = whitelist_table; id->match_flags; id++) {
++#ifdef DEBUG
++                      dev_dbg(&dev->dev,
++                              "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
++                              id->idVendor,
++                              id->idProduct,
++                              id->bDeviceClass,
++                              id->bDeviceSubClass,
++                              id->bDeviceProtocol);
++#endif
+-      /* add other match criteria here ... */
++                      if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
++                          id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
++                              continue;
++
++                      if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
++                          id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
++                              continue;
++
++                      /* No need to test id->bcdDevice_lo != 0, since 0 is never
++                         greater than any unsigned number. */
++                      if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
++                          (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
++                              continue;
++
++                      if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
++                          (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
++                              continue;
++
++                      if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
++                          (id->bDeviceClass != dev->descriptor.bDeviceClass))
++                              continue;
++
++                      if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
++                          (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
++                              continue;
++
++                      if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
++                          (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
++                              continue;
++                      return 1;
++              }
++      }
+-      /* OTG MESSAGE: report errors here, customize to match your product */
+-      dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
+-              le16_to_cpu(dev->descriptor.idVendor),
+-              le16_to_cpu(dev->descriptor.idProduct));
++      /* add other match criteria here ... */
++      report_errors(dev);
+       return 0;
+ }
+--- /dev/null
++++ b/drivers/usb/gadget/file_storage.c
+@@ -0,0 +1,3676 @@
++/*
++ * file_storage.c -- File-backed USB Storage Gadget, for USB development
++ *
++ * Copyright (C) 2003-2008 Alan Stern
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions, and the following disclaimer,
++ *    without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ *    to endorse or promote products derived from this software without
++ *    specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/*
++ * The File-backed Storage Gadget acts as a USB Mass Storage device,
++ * appearing to the host as a disk drive or as a CD-ROM drive.  In addition
++ * to providing an example of a genuinely useful gadget driver for a USB
++ * device, it also illustrates a technique of double-buffering for increased
++ * throughput.  Last but not least, it gives an easy way to probe the
++ * behavior of the Mass Storage drivers in a USB host.
++ *
++ * Backing storage is provided by a regular file or a block device, specified
++ * by the "file" module parameter.  Access can be limited to read-only by
++ * setting the optional "ro" module parameter.  (For CD-ROM emulation,
++ * access is always read-only.)  The gadget will indicate that it has
++ * removable media if the optional "removable" module parameter is set.
++ *
++ * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
++ * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
++ * by the optional "transport" module parameter.  It also supports the
++ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
++ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
++ * the optional "protocol" module parameter.  In addition, the default
++ * Vendor ID, Product ID, release number and serial number can be overridden.
++ *
++ * There is support for multiple logical units (LUNs), each of which has
++ * its own backing file.  The number of LUNs can be set using the optional
++ * "luns" module parameter (anywhere from 1 to 8), and the corresponding
++ * files are specified using comma-separated lists for "file" and "ro".
++ * The default number of LUNs is taken from the number of "file" elements;
++ * it is 1 if "file" is not given.  If "removable" is not set then a backing
++ * file must be specified for each LUN.  If it is set, then an unspecified
++ * or empty backing filename means the LUN's medium is not loaded.  Ideally
++ * each LUN would be settable independently as a disk drive or a CD-ROM
++ * drive, but currently all LUNs have to be the same type.  The CD-ROM
++ * emulation includes a single data track and no audio tracks; hence there
++ * need be only one backing file per LUN.
++ *
++ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
++ * needed (an interrupt-out endpoint is also needed for CBI).  The memory
++ * requirement amounts to two 16K buffers, size configurable by a parameter.
++ * Support is included for both full-speed and high-speed operation.
++ *
++ * Note that the driver is slightly non-portable in that it assumes a
++ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
++ * interrupt-in endpoints.  With most device controllers this isn't an
++ * issue, but there may be some with hardware restrictions that prevent
++ * a buffer from being used by more than one endpoint.
++ *
++ * Module options:
++ *
++ *    file=filename[,filename...]
++ *                            Required if "removable" is not set, names of
++ *                                    the files or block devices used for
++ *                                    backing storage
++ *    serial=HHHH...          Required serial number (string of hex chars)
++ *    ro=b[,b...]             Default false, booleans for read-only access
++ *    removable               Default false, boolean for removable media
++ *    luns=N                  Default N = number of filenames, number of
++ *                                    LUNs to support
++ *    nofua=b[,b...]          Default false, booleans for ignore FUA flag
++ *                                    in SCSI WRITE(10,12) commands
++ *    stall                   Default determined according to the type of
++ *                                    USB device controller (usually true),
++ *                                    boolean to permit the driver to halt
++ *                                    bulk endpoints
++ *    cdrom                   Default false, boolean for whether to emulate
++ *                                    a CD-ROM drive
++ *    transport=XXX           Default BBB, transport name (CB, CBI, or BBB)
++ *    protocol=YYY            Default SCSI, protocol name (RBC, 8020 or
++ *                                    ATAPI, QIC, UFI, 8070, or SCSI;
++ *                                    also 1 - 6)
++ *    vendor=0xVVVV           Default 0x0525 (NetChip), USB Vendor ID
++ *    product=0xPPPP          Default 0xa4a5 (FSG), USB Product ID
++ *    release=0xRRRR          Override the USB release number (bcdDevice)
++ *    buflen=N                Default N=16384, buffer size used (will be
++ *                                    rounded down to a multiple of
++ *                                    PAGE_CACHE_SIZE)
++ *
++ * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
++ * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
++ * default values are used for everything else.
++ *
++ * The pathnames of the backing files and the ro settings are available in
++ * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
++ * the gadget's sysfs directory.  If the "removable" option is set, writing to
++ * these files will simulate ejecting/loading the medium (writing an empty
++ * line means eject) and adjusting a write-enable tab.  Changes to the ro
++ * setting are not allowed when the medium is loaded or if CD-ROM emulation
++ * is being used.
++ *
++ * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
++ * The driver's SCSI command interface was based on the "Information
++ * technology - Small Computer System Interface - 2" document from
++ * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
++ * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>.  The single exception
++ * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
++ * "Universal Serial Bus Mass Storage Class UFI Command Specification"
++ * document, Revision 1.0, December 14, 1998, available at
++ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
++ */
++
++
++/*
++ *                            Driver Design
++ *
++ * The FSG driver is fairly straightforward.  There is a main kernel
++ * thread that handles most of the work.  Interrupt routines field
++ * callbacks from the controller driver: bulk- and interrupt-request
++ * completion notifications, endpoint-0 events, and disconnect events.
++ * Completion events are passed to the main thread by wakeup calls.  Many
++ * ep0 requests are handled at interrupt time, but SetInterface,
++ * SetConfiguration, and device reset requests are forwarded to the
++ * thread in the form of "exceptions" using SIGUSR1 signals (since they
++ * should interrupt any ongoing file I/O operations).
++ *
++ * The thread's main routine implements the standard command/data/status
++ * parts of a SCSI interaction.  It and its subroutines are full of tests
++ * for pending signals/exceptions -- all this polling is necessary since
++ * the kernel has no setjmp/longjmp equivalents.  (Maybe this is an
++ * indication that the driver really wants to be running in userspace.)
++ * An important point is that so long as the thread is alive it keeps an
++ * open reference to the backing file.  This will prevent unmounting
++ * the backing file's underlying filesystem and could cause problems
++ * during system shutdown, for example.  To prevent such problems, the
++ * thread catches INT, TERM, and KILL signals and converts them into
++ * an EXIT exception.
++ *
++ * In normal operation the main thread is started during the gadget's
++ * fsg_bind() callback and stopped during fsg_unbind().  But it can also
++ * exit when it receives a signal, and there's no point leaving the
++ * gadget running when the thread is dead.  So just before the thread
++ * exits, it deregisters the gadget driver.  This makes things a little
++ * tricky: The driver is deregistered at two places, and the exiting
++ * thread can indirectly call fsg_unbind() which in turn can tell the
++ * thread to exit.  The first problem is resolved through the use of the
++ * REGISTERED atomic bitflag; the driver will only be deregistered once.
++ * The second problem is resolved by having fsg_unbind() check
++ * fsg->state; it won't try to stop the thread if the state is already
++ * FSG_STATE_TERMINATED.
++ *
++ * To provide maximum throughput, the driver uses a circular pipeline of
++ * buffer heads (struct fsg_buffhd).  In principle the pipeline can be
++ * arbitrarily long; in practice the benefits don't justify having more
++ * than 2 stages (i.e., double buffering).  But it helps to think of the
++ * pipeline as being a long one.  Each buffer head contains a bulk-in and
++ * a bulk-out request pointer (since the buffer can be used for both
++ * output and input -- directions always are given from the host's
++ * point of view) as well as a pointer to the buffer and various state
++ * variables.
++ *
++ * Use of the pipeline follows a simple protocol.  There is a variable
++ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
++ * At any time that buffer head may still be in use from an earlier
++ * request, so each buffer head has a state variable indicating whether
++ * it is EMPTY, FULL, or BUSY.  Typical use involves waiting for the
++ * buffer head to be EMPTY, filling the buffer either by file I/O or by
++ * USB I/O (during which the buffer head is BUSY), and marking the buffer
++ * head FULL when the I/O is complete.  Then the buffer will be emptied
++ * (again possibly by USB I/O, during which it is marked BUSY) and
++ * finally marked EMPTY again (possibly by a completion routine).
++ *
++ * A module parameter tells the driver to avoid stalling the bulk
++ * endpoints wherever the transport specification allows.  This is
++ * necessary for some UDCs like the SuperH, which cannot reliably clear a
++ * halt on a bulk endpoint.  However, under certain circumstances the
++ * Bulk-only specification requires a stall.  In such cases the driver
++ * will halt the endpoint and set a flag indicating that it should clear
++ * the halt in software during the next device reset.  Hopefully this
++ * will permit everything to work correctly.  Furthermore, although the
++ * specification allows the bulk-out endpoint to halt when the host sends
++ * too much data, implementing this would cause an unavoidable race.
++ * The driver will always use the "no-stall" approach for OUT transfers.
++ *
++ * One subtle point concerns sending status-stage responses for ep0
++ * requests.  Some of these requests, such as device reset, can involve
++ * interrupting an ongoing file I/O operation, which might take an
++ * arbitrarily long time.  During that delay the host might give up on
++ * the original ep0 request and issue a new one.  When that happens the
++ * driver should not notify the host about completion of the original
++ * request, as the host will no longer be waiting for it.  So the driver
++ * assigns to each ep0 request a unique tag, and it keeps track of the
++ * tag value of the request associated with a long-running exception
++ * (device-reset, interface-change, or configuration-change).  When the
++ * exception handler is finished, the status-stage response is submitted
++ * only if the current ep0 request tag is equal to the exception request
++ * tag.  Thus only the most recently received ep0 request will get a
++ * status-stage response.
++ *
++ * Warning: This driver source file is too long.  It ought to be split up
++ * into a header file plus about 3 separate .c files, to handle the details
++ * of the Gadget, USB Mass Storage, and SCSI protocols.
++ */
++
++
++/* #define VERBOSE_DEBUG */
++/* #define DUMP_MSGS */
++
++
++#include <linux/blkdev.h>
++#include <linux/completion.h>
++#include <linux/dcache.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/fcntl.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/kref.h>
++#include <linux/kthread.h>
++#include <linux/limits.h>
++#include <linux/module.h>
++#include <linux/rwsem.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/freezer.h>
++#include <linux/utsname.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#include "gadget_chips.h"
++
++
++
++/*
++ * Kbuild is not very cooperative with respect to linking separately
++ * compiled library objects into one module.  So for now we won't use
++ * separate compilation ... ensuring init/exit sections work to shrink
++ * the runtime footprint, and giving us at least some parts of what
++ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
++ */
++#include "usbstring.c"
++#include "config.c"
++#include "epautoconf.c"
++
++/*-------------------------------------------------------------------------*/
++
++#define DRIVER_DESC           "File-backed Storage Gadget"
++#define DRIVER_NAME           "g_file_storage"
++#define DRIVER_VERSION                "1 September 2010"
++
++static       char fsg_string_manufacturer[64];
++static const char fsg_string_product[] = DRIVER_DESC;
++static const char fsg_string_config[] = "Self-powered";
++static const char fsg_string_interface[] = "Mass Storage";
++
++
++#include "storage_common.c"
++
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Alan Stern");
++MODULE_LICENSE("Dual BSD/GPL");
++
++/*
++ * This driver assumes self-powered hardware and has no way for users to
++ * trigger remote wakeup.  It uses autoconfiguration to select endpoints
++ * and endpoint addresses.
++ */
++
++
++/*-------------------------------------------------------------------------*/
++
++
++/* Encapsulate the module parameter settings */
++
++static struct {
++      char            *file[FSG_MAX_LUNS];
++      char            *serial;
++      bool            ro[FSG_MAX_LUNS];
++      bool            nofua[FSG_MAX_LUNS];
++      unsigned int    num_filenames;
++      unsigned int    num_ros;
++      unsigned int    num_nofuas;
++      unsigned int    nluns;
++
++      bool            removable;
++      bool            can_stall;
++      bool            cdrom;
++
++      char            *transport_parm;
++      char            *protocol_parm;
++      unsigned short  vendor;
++      unsigned short  product;
++      unsigned short  release;
++      unsigned int    buflen;
++
++      int             transport_type;
++      char            *transport_name;
++      int             protocol_type;
++      char            *protocol_name;
++
++} mod_data = {                                        // Default values
++      .transport_parm         = "BBB",
++      .protocol_parm          = "SCSI",
++      .removable              = 0,
++      .can_stall              = 1,
++      .cdrom                  = 0,
++      .vendor                 = FSG_VENDOR_ID,
++      .product                = FSG_PRODUCT_ID,
++      .release                = 0xffff,       // Use controller chip type
++      .buflen                 = 16384,
++      };
++
++
++module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
++              S_IRUGO);
++MODULE_PARM_DESC(file, "names of backing files or devices");
++
++module_param_named(serial, mod_data.serial, charp, S_IRUGO);
++MODULE_PARM_DESC(serial, "USB serial number");
++
++module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
++MODULE_PARM_DESC(ro, "true to force read-only");
++
++module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
++              S_IRUGO);
++MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
++
++module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
++MODULE_PARM_DESC(luns, "number of LUNs");
++
++module_param_named(removable, mod_data.removable, bool, S_IRUGO);
++MODULE_PARM_DESC(removable, "true to simulate removable media");
++
++module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
++MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
++
++module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
++MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
++
++/* In the non-TEST version, only the module parameters listed above
++ * are available. */
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++
++module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
++MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
++
++module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
++MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
++              "8070, or SCSI)");
++
++module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
++MODULE_PARM_DESC(vendor, "USB Vendor ID");
++
++module_param_named(product, mod_data.product, ushort, S_IRUGO);
++MODULE_PARM_DESC(product, "USB Product ID");
++
++module_param_named(release, mod_data.release, ushort, S_IRUGO);
++MODULE_PARM_DESC(release, "USB release number");
++
++module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
++MODULE_PARM_DESC(buflen, "I/O buffer size");
++
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*
++ * These definitions will permit the compiler to avoid generating code for
++ * parts of the driver that aren't used in the non-TEST version.  Even gcc
++ * can recognize when a test of a constant expression yields a dead code
++ * path.
++ */
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++
++#define transport_is_bbb()    (mod_data.transport_type == USB_PR_BULK)
++#define transport_is_cbi()    (mod_data.transport_type == USB_PR_CBI)
++#define protocol_is_scsi()    (mod_data.protocol_type == USB_SC_SCSI)
++
++#else
++
++#define transport_is_bbb()    1
++#define transport_is_cbi()    0
++#define protocol_is_scsi()    1
++
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*-------------------------------------------------------------------------*/
++
++
++struct fsg_dev {
++      /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
++      spinlock_t              lock;
++      struct usb_gadget       *gadget;
++
++      /* filesem protects: backing files in use */
++      struct rw_semaphore     filesem;
++
++      /* reference counting: wait until all LUNs are released */
++      struct kref             ref;
++
++      struct usb_ep           *ep0;           // Handy copy of gadget->ep0
++      struct usb_request      *ep0req;        // For control responses
++      unsigned int            ep0_req_tag;
++      const char              *ep0req_name;
++
++      struct usb_request      *intreq;        // For interrupt responses
++      int                     intreq_busy;
++      struct fsg_buffhd       *intr_buffhd;
++
++      unsigned int            bulk_out_maxpacket;
++      enum fsg_state          state;          // For exception handling
++      unsigned int            exception_req_tag;
++
++      u8                      config, new_config;
++
++      unsigned int            running : 1;
++      unsigned int            bulk_in_enabled : 1;
++      unsigned int            bulk_out_enabled : 1;
++      unsigned int            intr_in_enabled : 1;
++      unsigned int            phase_error : 1;
++      unsigned int            short_packet_received : 1;
++      unsigned int            bad_lun_okay : 1;
++
++      unsigned long           atomic_bitflags;
++#define REGISTERED            0
++#define IGNORE_BULK_OUT               1
++#define SUSPENDED             2
++
++      struct usb_ep           *bulk_in;
++      struct usb_ep           *bulk_out;
++      struct usb_ep           *intr_in;
++
++      struct fsg_buffhd       *next_buffhd_to_fill;
++      struct fsg_buffhd       *next_buffhd_to_drain;
++
++      int                     thread_wakeup_needed;
++      struct completion       thread_notifier;
++      struct task_struct      *thread_task;
++
++      int                     cmnd_size;
++      u8                      cmnd[MAX_COMMAND_SIZE];
++      enum data_direction     data_dir;
++      u32                     data_size;
++      u32                     data_size_from_cmnd;
++      u32                     tag;
++      unsigned int            lun;
++      u32                     residue;
++      u32                     usb_amount_left;
++
++      /* The CB protocol offers no way for a host to know when a command
++       * has completed.  As a result the next command may arrive early,
++       * and we will still have to handle it.  For that reason we need
++       * a buffer to store new commands when using CB (or CBI, which
++       * does not oblige a host to wait for command completion either). */
++      int                     cbbuf_cmnd_size;
++      u8                      cbbuf_cmnd[MAX_COMMAND_SIZE];
++
++      unsigned int            nluns;
++      struct fsg_lun          *luns;
++      struct fsg_lun          *curlun;
++      /* Must be the last entry */
++      struct fsg_buffhd       buffhds[];
++};
++
++typedef void (*fsg_routine_t)(struct fsg_dev *);
++
++static int exception_in_progress(struct fsg_dev *fsg)
++{
++      return (fsg->state > FSG_STATE_IDLE);
++}
++
++/* Make bulk-out requests be divisible by the maxpacket size */
++static void set_bulk_out_req_length(struct fsg_dev *fsg,
++              struct fsg_buffhd *bh, unsigned int length)
++{
++      unsigned int    rem;
++
++      bh->bulk_out_intended_length = length;
++      rem = length % fsg->bulk_out_maxpacket;
++      if (rem > 0)
++              length += fsg->bulk_out_maxpacket - rem;
++      bh->outreq->length = length;
++}
++
++static struct fsg_dev                 *the_fsg;
++static struct usb_gadget_driver               fsg_driver;
++
++
++/*-------------------------------------------------------------------------*/
++
++static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
++{
++      const char      *name;
++
++      if (ep == fsg->bulk_in)
++              name = "bulk-in";
++      else if (ep == fsg->bulk_out)
++              name = "bulk-out";
++      else
++              name = ep->name;
++      DBG(fsg, "%s set halt\n", name);
++      return usb_ep_set_halt(ep);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * DESCRIPTORS ... most are static, but strings and (full) configuration
++ * descriptors are built on demand.  Also the (static) config and interface
++ * descriptors are adjusted during fsg_bind().
++ */
++
++/* There is only one configuration. */
++#define       CONFIG_VALUE            1
++
++static struct usb_device_descriptor
++device_desc = {
++      .bLength =              sizeof device_desc,
++      .bDescriptorType =      USB_DT_DEVICE,
++
++      .bcdUSB =               cpu_to_le16(0x0200),
++      .bDeviceClass =         USB_CLASS_PER_INTERFACE,
++
++      /* The next three values can be overridden by module parameters */
++      .idVendor =             cpu_to_le16(FSG_VENDOR_ID),
++      .idProduct =            cpu_to_le16(FSG_PRODUCT_ID),
++      .bcdDevice =            cpu_to_le16(0xffff),
++
++      .iManufacturer =        FSG_STRING_MANUFACTURER,
++      .iProduct =             FSG_STRING_PRODUCT,
++      .iSerialNumber =        FSG_STRING_SERIAL,
++      .bNumConfigurations =   1,
++};
++
++static struct usb_config_descriptor
++config_desc = {
++      .bLength =              sizeof config_desc,
++      .bDescriptorType =      USB_DT_CONFIG,
++
++      /* wTotalLength computed by usb_gadget_config_buf() */
++      .bNumInterfaces =       1,
++      .bConfigurationValue =  CONFIG_VALUE,
++      .iConfiguration =       FSG_STRING_CONFIG,
++      .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
++      .bMaxPower =            CONFIG_USB_GADGET_VBUS_DRAW / 2,
++};
++
++
++static struct usb_qualifier_descriptor
++dev_qualifier = {
++      .bLength =              sizeof dev_qualifier,
++      .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
++
++      .bcdUSB =               cpu_to_le16(0x0200),
++      .bDeviceClass =         USB_CLASS_PER_INTERFACE,
++
++      .bNumConfigurations =   1,
++};
++
++static int populate_bos(struct fsg_dev *fsg, u8 *buf)
++{
++      memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
++      buf += USB_DT_BOS_SIZE;
++
++      memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
++      buf += USB_DT_USB_EXT_CAP_SIZE;
++
++      memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
++
++      return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
++              + USB_DT_USB_EXT_CAP_SIZE;
++}
++
++/*
++ * Config descriptors must agree with the code that sets configurations
++ * and with code managing interfaces and their altsettings.  They must
++ * also handle different speeds and other-speed requests.
++ */
++static int populate_config_buf(struct usb_gadget *gadget,
++              u8 *buf, u8 type, unsigned index)
++{
++      enum usb_device_speed                   speed = gadget->speed;
++      int                                     len;
++      const struct usb_descriptor_header      **function;
++
++      if (index > 0)
++              return -EINVAL;
++
++      if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
++              speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
++      function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
++              ? (const struct usb_descriptor_header **)fsg_hs_function
++              : (const struct usb_descriptor_header **)fsg_fs_function;
++
++      /* for now, don't advertise srp-only devices */
++      if (!gadget_is_otg(gadget))
++              function++;
++
++      len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
++      ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
++      return len;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* These routines may be called in process context or in_irq */
++
++/* Caller must hold fsg->lock */
++static void wakeup_thread(struct fsg_dev *fsg)
++{
++      /* Tell the main thread that something has happened */
++      fsg->thread_wakeup_needed = 1;
++      if (fsg->thread_task)
++              wake_up_process(fsg->thread_task);
++}
++
++
++static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
++{
++      unsigned long           flags;
++
++      /* Do nothing if a higher-priority exception is already in progress.
++       * If a lower-or-equal priority exception is in progress, preempt it
++       * and notify the main thread by sending it a signal. */
++      spin_lock_irqsave(&fsg->lock, flags);
++      if (fsg->state <= new_state) {
++              fsg->exception_req_tag = fsg->ep0_req_tag;
++              fsg->state = new_state;
++              if (fsg->thread_task)
++                      send_sig_info(SIGUSR1, SEND_SIG_FORCED,
++                                      fsg->thread_task);
++      }
++      spin_unlock_irqrestore(&fsg->lock, flags);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* The disconnect callback and ep0 routines.  These always run in_irq,
++ * except that ep0_queue() is called in the main thread to acknowledge
++ * completion of various requests: set config, set interface, and
++ * Bulk-only device reset. */
++
++static void fsg_disconnect(struct usb_gadget *gadget)
++{
++      struct fsg_dev          *fsg = get_gadget_data(gadget);
++
++      DBG(fsg, "disconnect or port reset\n");
++      raise_exception(fsg, FSG_STATE_DISCONNECT);
++}
++
++
++static int ep0_queue(struct fsg_dev *fsg)
++{
++      int     rc;
++
++      rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
++      if (rc != 0 && rc != -ESHUTDOWN) {
++
++              /* We can't do much more than wait for a reset */
++              WARNING(fsg, "error in submission: %s --> %d\n",
++                              fsg->ep0->name, rc);
++      }
++      return rc;
++}
++
++static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct fsg_dev          *fsg = ep->driver_data;
++
++      if (req->actual > 0)
++              dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
++      if (req->status || req->actual != req->length)
++              DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++                              req->status, req->actual, req->length);
++      if (req->status == -ECONNRESET)         // Request was cancelled
++              usb_ep_fifo_flush(ep);
++
++      if (req->status == 0 && req->context)
++              ((fsg_routine_t) (req->context))(fsg);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Bulk and interrupt endpoint completion handlers.
++ * These always run in_irq. */
++
++static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct fsg_dev          *fsg = ep->driver_data;
++      struct fsg_buffhd       *bh = req->context;
++
++      if (req->status || req->actual != req->length)
++              DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++                              req->status, req->actual, req->length);
++      if (req->status == -ECONNRESET)         // Request was cancelled
++              usb_ep_fifo_flush(ep);
++
++      /* Hold the lock while we update the request and buffer states */
++      smp_wmb();
++      spin_lock(&fsg->lock);
++      bh->inreq_busy = 0;
++      bh->state = BUF_STATE_EMPTY;
++      wakeup_thread(fsg);
++      spin_unlock(&fsg->lock);
++}
++
++static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct fsg_dev          *fsg = ep->driver_data;
++      struct fsg_buffhd       *bh = req->context;
++
++      dump_msg(fsg, "bulk-out", req->buf, req->actual);
++      if (req->status || req->actual != bh->bulk_out_intended_length)
++              DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++                              req->status, req->actual,
++                              bh->bulk_out_intended_length);
++      if (req->status == -ECONNRESET)         // Request was cancelled
++              usb_ep_fifo_flush(ep);
++
++      /* Hold the lock while we update the request and buffer states */
++      smp_wmb();
++      spin_lock(&fsg->lock);
++      bh->outreq_busy = 0;
++      bh->state = BUF_STATE_FULL;
++      wakeup_thread(fsg);
++      spin_unlock(&fsg->lock);
++}
++
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
++{
++      struct fsg_dev          *fsg = ep->driver_data;
++      struct fsg_buffhd       *bh = req->context;
++
++      if (req->status || req->actual != req->length)
++              DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++                              req->status, req->actual, req->length);
++      if (req->status == -ECONNRESET)         // Request was cancelled
++              usb_ep_fifo_flush(ep);
++
++      /* Hold the lock while we update the request and buffer states */
++      smp_wmb();
++      spin_lock(&fsg->lock);
++      fsg->intreq_busy = 0;
++      bh->state = BUF_STATE_EMPTY;
++      wakeup_thread(fsg);
++      spin_unlock(&fsg->lock);
++}
++
++#else
++static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
++{}
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Ep0 class-specific handlers.  These always run in_irq. */
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++      struct usb_request      *req = fsg->ep0req;
++      static u8               cbi_reset_cmnd[6] = {
++                      SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
++
++      /* Error in command transfer? */
++      if (req->status || req->length != req->actual ||
++                      req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
++
++              /* Not all controllers allow a protocol stall after
++               * receiving control-out data, but we'll try anyway. */
++              fsg_set_halt(fsg, fsg->ep0);
++              return;                 // Wait for reset
++      }
++
++      /* Is it the special reset command? */
++      if (req->actual >= sizeof cbi_reset_cmnd &&
++                      memcmp(req->buf, cbi_reset_cmnd,
++                              sizeof cbi_reset_cmnd) == 0) {
++
++              /* Raise an exception to stop the current operation
++               * and reinitialize our state. */
++              DBG(fsg, "cbi reset request\n");
++              raise_exception(fsg, FSG_STATE_RESET);
++              return;
++      }
++
++      VDBG(fsg, "CB[I] accept device-specific command\n");
++      spin_lock(&fsg->lock);
++
++      /* Save the command for later */
++      if (fsg->cbbuf_cmnd_size)
++              WARNING(fsg, "CB[I] overwriting previous command\n");
++      fsg->cbbuf_cmnd_size = req->actual;
++      memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
++
++      wakeup_thread(fsg);
++      spin_unlock(&fsg->lock);
++}
++
++#else
++static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{}
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++static int class_setup_req(struct fsg_dev *fsg,
++              const struct usb_ctrlrequest *ctrl)
++{
++      struct usb_request      *req = fsg->ep0req;
++      int                     value = -EOPNOTSUPP;
++      u16                     w_index = le16_to_cpu(ctrl->wIndex);
++      u16                     w_value = le16_to_cpu(ctrl->wValue);
++      u16                     w_length = le16_to_cpu(ctrl->wLength);
++
++      if (!fsg->config)
++              return value;
++
++      /* Handle Bulk-only class-specific requests */
++      if (transport_is_bbb()) {
++              switch (ctrl->bRequest) {
++
++              case US_BULK_RESET_REQUEST:
++                      if (ctrl->bRequestType != (USB_DIR_OUT |
++                                      USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++                              break;
++                      if (w_index != 0 || w_value != 0 || w_length != 0) {
++                              value = -EDOM;
++                              break;
++                      }
++
++                      /* Raise an exception to stop the current operation
++                       * and reinitialize our state. */
++                      DBG(fsg, "bulk reset request\n");
++                      raise_exception(fsg, FSG_STATE_RESET);
++                      value = DELAYED_STATUS;
++                      break;
++
++              case US_BULK_GET_MAX_LUN:
++                      if (ctrl->bRequestType != (USB_DIR_IN |
++                                      USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++                              break;
++                      if (w_index != 0 || w_value != 0 || w_length != 1) {
++                              value = -EDOM;
++                              break;
++                      }
++                      VDBG(fsg, "get max LUN\n");
++                      *(u8 *) req->buf = fsg->nluns - 1;
++                      value = 1;
++                      break;
++              }
++      }
++
++      /* Handle CBI class-specific requests */
++      else {
++              switch (ctrl->bRequest) {
++
++              case USB_CBI_ADSC_REQUEST:
++                      if (ctrl->bRequestType != (USB_DIR_OUT |
++                                      USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++                              break;
++                      if (w_index != 0 || w_value != 0) {
++                              value = -EDOM;
++                              break;
++                      }
++                      if (w_length > MAX_COMMAND_SIZE) {
++                              value = -EOVERFLOW;
++                              break;
++                      }
++                      value = w_length;
++                      fsg->ep0req->context = received_cbi_adsc;
++                      break;
++              }
++      }
++
++      if (value == -EOPNOTSUPP)
++              VDBG(fsg,
++                      "unknown class-specific control req "
++                      "%02x.%02x v%04x i%04x l%u\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      le16_to_cpu(ctrl->wValue), w_index, w_length);
++      return value;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Ep0 standard request handlers.  These always run in_irq. */
++
++static int standard_setup_req(struct fsg_dev *fsg,
++              const struct usb_ctrlrequest *ctrl)
++{
++      struct usb_request      *req = fsg->ep0req;
++      int                     value = -EOPNOTSUPP;
++      u16                     w_index = le16_to_cpu(ctrl->wIndex);
++      u16                     w_value = le16_to_cpu(ctrl->wValue);
++
++      /* Usually this just stores reply data in the pre-allocated ep0 buffer,
++       * but config change events will also reconfigure hardware. */
++      switch (ctrl->bRequest) {
++
++      case USB_REQ_GET_DESCRIPTOR:
++              if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++                              USB_RECIP_DEVICE))
++                      break;
++              switch (w_value >> 8) {
++
++              case USB_DT_DEVICE:
++                      VDBG(fsg, "get device descriptor\n");
++                      device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
++                      value = sizeof device_desc;
++                      memcpy(req->buf, &device_desc, value);
++                      break;
++              case USB_DT_DEVICE_QUALIFIER:
++                      VDBG(fsg, "get device qualifier\n");
++                      if (!gadget_is_dualspeed(fsg->gadget) ||
++                                      fsg->gadget->speed == USB_SPEED_SUPER)
++                              break;
++                      /*
++                       * Assume ep0 uses the same maxpacket value for both
++                       * speeds
++                       */
++                      dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
++                      value = sizeof dev_qualifier;
++                      memcpy(req->buf, &dev_qualifier, value);
++                      break;
++
++              case USB_DT_OTHER_SPEED_CONFIG:
++                      VDBG(fsg, "get other-speed config descriptor\n");
++                      if (!gadget_is_dualspeed(fsg->gadget) ||
++                                      fsg->gadget->speed == USB_SPEED_SUPER)
++                              break;
++                      goto get_config;
++              case USB_DT_CONFIG:
++                      VDBG(fsg, "get configuration descriptor\n");
++get_config:
++                      value = populate_config_buf(fsg->gadget,
++                                      req->buf,
++                                      w_value >> 8,
++                                      w_value & 0xff);
++                      break;
++
++              case USB_DT_STRING:
++                      VDBG(fsg, "get string descriptor\n");
++
++                      /* wIndex == language code */
++                      value = usb_gadget_get_string(&fsg_stringtab,
++                                      w_value & 0xff, req->buf);
++                      break;
++
++              case USB_DT_BOS:
++                      VDBG(fsg, "get bos descriptor\n");
++
++                      if (gadget_is_superspeed(fsg->gadget))
++                              value = populate_bos(fsg, req->buf);
++                      break;
++              }
++
++              break;
++
++      /* One config, two speeds */
++      case USB_REQ_SET_CONFIGURATION:
++              if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
++                              USB_RECIP_DEVICE))
++                      break;
++              VDBG(fsg, "set configuration\n");
++              if (w_value == CONFIG_VALUE || w_value == 0) {
++                      fsg->new_config = w_value;
++
++                      /* Raise an exception to wipe out previous transaction
++                       * state (queued bufs, etc) and set the new config. */
++                      raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
++                      value = DELAYED_STATUS;
++              }
++              break;
++      case USB_REQ_GET_CONFIGURATION:
++              if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++                              USB_RECIP_DEVICE))
++                      break;
++              VDBG(fsg, "get configuration\n");
++              *(u8 *) req->buf = fsg->config;
++              value = 1;
++              break;
++
++      case USB_REQ_SET_INTERFACE:
++              if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
++                              USB_RECIP_INTERFACE))
++                      break;
++              if (fsg->config && w_index == 0) {
++
++                      /* Raise an exception to wipe out previous transaction
++                       * state (queued bufs, etc) and install the new
++                       * interface altsetting. */
++                      raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
++                      value = DELAYED_STATUS;
++              }
++              break;
++      case USB_REQ_GET_INTERFACE:
++              if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++                              USB_RECIP_INTERFACE))
++                      break;
++              if (!fsg->config)
++                      break;
++              if (w_index != 0) {
++                      value = -EDOM;
++                      break;
++              }
++              VDBG(fsg, "get interface\n");
++              *(u8 *) req->buf = 0;
++              value = 1;
++              break;
++
++      default:
++              VDBG(fsg,
++                      "unknown control req %02x.%02x v%04x i%04x l%u\n",
++                      ctrl->bRequestType, ctrl->bRequest,
++                      w_value, w_index, le16_to_cpu(ctrl->wLength));
++      }
++
++      return value;
++}
++
++
++static int fsg_setup(struct usb_gadget *gadget,
++              const struct usb_ctrlrequest *ctrl)
++{
++      struct fsg_dev          *fsg = get_gadget_data(gadget);
++      int                     rc;
++      int                     w_length = le16_to_cpu(ctrl->wLength);
++
++      ++fsg->ep0_req_tag;             // Record arrival of a new request
++      fsg->ep0req->context = NULL;
++      fsg->ep0req->length = 0;
++      dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
++
++      if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
++              rc = class_setup_req(fsg, ctrl);
++      else
++              rc = standard_setup_req(fsg, ctrl);
++
++      /* Respond with data/status or defer until later? */
++      if (rc >= 0 && rc != DELAYED_STATUS) {
++              rc = min(rc, w_length);
++              fsg->ep0req->length = rc;
++              fsg->ep0req->zero = rc < w_length;
++              fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
++                              "ep0-in" : "ep0-out");
++              rc = ep0_queue(fsg);
++      }
++
++      /* Device either stalls (rc < 0) or reports success */
++      return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* All the following routines run in process context */
++
++
++/* Use this for bulk or interrupt transfers, not ep0 */
++static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
++              struct usb_request *req, int *pbusy,
++              enum fsg_buffer_state *state)
++{
++      int     rc;
++
++      if (ep == fsg->bulk_in)
++              dump_msg(fsg, "bulk-in", req->buf, req->length);
++      else if (ep == fsg->intr_in)
++              dump_msg(fsg, "intr-in", req->buf, req->length);
++
++      spin_lock_irq(&fsg->lock);
++      *pbusy = 1;
++      *state = BUF_STATE_BUSY;
++      spin_unlock_irq(&fsg->lock);
++      rc = usb_ep_queue(ep, req, GFP_KERNEL);
++      if (rc != 0) {
++              *pbusy = 0;
++              *state = BUF_STATE_EMPTY;
++
++              /* We can't do much more than wait for a reset */
++
++              /* Note: currently the net2280 driver fails zero-length
++               * submissions if DMA is enabled. */
++              if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
++                                              req->length == 0))
++                      WARNING(fsg, "error in submission: %s --> %d\n",
++                                      ep->name, rc);
++      }
++}
++
++
++static int sleep_thread(struct fsg_dev *fsg)
++{
++      int     rc = 0;
++
++      /* Wait until a signal arrives or we are woken up */
++      for (;;) {
++              try_to_freeze();
++              set_current_state(TASK_INTERRUPTIBLE);
++              if (signal_pending(current)) {
++                      rc = -EINTR;
++                      break;
++              }
++              if (fsg->thread_wakeup_needed)
++                      break;
++              schedule();
++      }
++      __set_current_state(TASK_RUNNING);
++      fsg->thread_wakeup_needed = 0;
++      return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_read(struct fsg_dev *fsg)
++{
++      struct fsg_lun          *curlun = fsg->curlun;
++      u32                     lba;
++      struct fsg_buffhd       *bh;
++      int                     rc;
++      u32                     amount_left;
++      loff_t                  file_offset, file_offset_tmp;
++      unsigned int            amount;
++      ssize_t                 nread;
++
++      /* Get the starting Logical Block Address and check that it's
++       * not too big */
++      if (fsg->cmnd[0] == READ_6)
++              lba = get_unaligned_be24(&fsg->cmnd[1]);
++      else {
++              lba = get_unaligned_be32(&fsg->cmnd[2]);
++
++              /* We allow DPO (Disable Page Out = don't save data in the
++               * cache) and FUA (Force Unit Access = don't read from the
++               * cache), but we don't implement them. */
++              if ((fsg->cmnd[1] & ~0x18) != 0) {
++                      curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++                      return -EINVAL;
++              }
++      }
++      if (lba >= curlun->num_sectors) {
++              curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++              return -EINVAL;
++      }
++      file_offset = ((loff_t) lba) << curlun->blkbits;
++
++      /* Carry out the file reads */
++      amount_left = fsg->data_size_from_cmnd;
++      if (unlikely(amount_left == 0))
++              return -EIO;            // No default reply
++
++      for (;;) {
++
++              /* Figure out how much we need to read:
++               * Try to read the remaining amount.
++               * But don't read more than the buffer size.
++               * And don't try to read past the end of the file.
++               */
++              amount = min((unsigned int) amount_left, mod_data.buflen);
++              amount = min((loff_t) amount,
++                              curlun->file_length - file_offset);
++
++              /* Wait for the next buffer to become available */
++              bh = fsg->next_buffhd_to_fill;
++              while (bh->state != BUF_STATE_EMPTY) {
++                      rc = sleep_thread(fsg);
++                      if (rc)
++                              return rc;
++              }
++
++              /* If we were asked to read past the end of file,
++               * end with an empty buffer. */
++              if (amount == 0) {
++                      curlun->sense_data =
++                                      SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++                      curlun->sense_data_info = file_offset >> curlun->blkbits;
++                      curlun->info_valid = 1;
++                      bh->inreq->length = 0;
++                      bh->state = BUF_STATE_FULL;
++                      break;
++              }
++
++              /* Perform the read */
++              file_offset_tmp = file_offset;
++              nread = vfs_read(curlun->filp,
++                              (char __user *) bh->buf,
++                              amount, &file_offset_tmp);
++              VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
++                              (unsigned long long) file_offset,
++                              (int) nread);
++              if (signal_pending(current))
++                      return -EINTR;
++
++              if (nread < 0) {
++                      LDBG(curlun, "error in file read: %d\n",
++                                      (int) nread);
++                      nread = 0;
++              } else if (nread < amount) {
++                      LDBG(curlun, "partial file read: %d/%u\n",
++                                      (int) nread, amount);
++                      nread = round_down(nread, curlun->blksize);
++              }
++              file_offset  += nread;
++              amount_left  -= nread;
++              fsg->residue -= nread;
++
++              /* Except at the end of the transfer, nread will be
++               * equal to the buffer size, which is divisible by the
++               * bulk-in maxpacket size.
++               */
++              bh->inreq->length = nread;
++              bh->state = BUF_STATE_FULL;
++
++              /* If an error occurred, report it and its position */
++              if (nread < amount) {
++                      curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
++                      curlun->sense_data_info = file_offset >> curlun->blkbits;
++                      curlun->info_valid = 1;
++                      break;
++              }
++
++              if (amount_left == 0)
++                      break;          // No more left to read
++
++              /* Send this buffer and go read some more */
++              bh->inreq->zero = 0;
++              start_transfer(fsg, fsg->bulk_in, bh->inreq,
++                              &bh->inreq_busy, &bh->state);
++              fsg->next_buffhd_to_fill = bh->next;
++      }
++
++      return -EIO;            // No default reply
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_write(struct fsg_dev *fsg)
++{
++      struct fsg_lun          *curlun = fsg->curlun;
++      u32                     lba;
++      struct fsg_buffhd       *bh;
++      int                     get_some_more;
++      u32                     amount_left_to_req, amount_left_to_write;
++      loff_t                  usb_offset, file_offset, file_offset_tmp;
++      unsigned int            amount;
++      ssize_t                 nwritten;
++      int                     rc;
++
++      if (curlun->ro) {
++              curlun->sense_data = SS_WRITE_PROTECTED;
++              return -EINVAL;
++      }
++      spin_lock(&curlun->filp->f_lock);
++      curlun->filp->f_flags &= ~O_SYNC;       // Default is not to wait
++      spin_unlock(&curlun->filp->f_lock);
++
++      /* Get the starting Logical Block Address and check that it's
++       * not too big */
++      if (fsg->cmnd[0] == WRITE_6)
++              lba = get_unaligned_be24(&fsg->cmnd[1]);
++      else {
++              lba = get_unaligned_be32(&fsg->cmnd[2]);
++
++              /* We allow DPO (Disable Page Out = don't save data in the
++               * cache) and FUA (Force Unit Access = write directly to the
++               * medium).  We don't implement DPO; we implement FUA by
++               * performing synchronous output. */
++              if ((fsg->cmnd[1] & ~0x18) != 0) {
++                      curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++                      return -EINVAL;
++              }
++              /* FUA */
++              if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
++                      spin_lock(&curlun->filp->f_lock);
++                      curlun->filp->f_flags |= O_DSYNC;
++                      spin_unlock(&curlun->filp->f_lock);
++              }
++      }
++      if (lba >= curlun->num_sectors) {
++              curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++              return -EINVAL;
++      }
++
++      /* Carry out the file writes */
++      get_some_more = 1;
++      file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
++      amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
++
++      while (amount_left_to_write > 0) {
++
++              /* Queue a request for more data from the host */
++              bh = fsg->next_buffhd_to_fill;
++              if (bh->state == BUF_STATE_EMPTY && get_some_more) {
++
++                      /* Figure out how much we want to get:
++                       * Try to get the remaining amount,
++                       * but not more than the buffer size.
++                       */
++                      amount = min(amount_left_to_req, mod_data.buflen);
++
++                      /* Beyond the end of the backing file? */
++                      if (usb_offset >= curlun->file_length) {
++                              get_some_more = 0;
++                              curlun->sense_data =
++                                      SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++                              curlun->sense_data_info = usb_offset >> curlun->blkbits;
++                              curlun->info_valid = 1;
++                              continue;
++                      }
++
++                      /* Get the next buffer */
++                      usb_offset += amount;
++                      fsg->usb_amount_left -= amount;
++                      amount_left_to_req -= amount;
++                      if (amount_left_to_req == 0)
++                              get_some_more = 0;
++
++                      /* Except at the end of the transfer, amount will be
++                       * equal to the buffer size, which is divisible by
++                       * the bulk-out maxpacket size.
++                       */
++                      set_bulk_out_req_length(fsg, bh, amount);
++                      start_transfer(fsg, fsg->bulk_out, bh->outreq,
++                                      &bh->outreq_busy, &bh->state);
++                      fsg->next_buffhd_to_fill = bh->next;
++                      continue;
++              }
++
++              /* Write the received data to the backing file */
++              bh = fsg->next_buffhd_to_drain;
++              if (bh->state == BUF_STATE_EMPTY && !get_some_more)
++                      break;                  // We stopped early
++              if (bh->state == BUF_STATE_FULL) {
++                      smp_rmb();
++                      fsg->next_buffhd_to_drain = bh->next;
++                      bh->state = BUF_STATE_EMPTY;
++
++                      /* Did something go wrong with the transfer? */
++                      if (bh->outreq->status != 0) {
++                              curlun->sense_data = SS_COMMUNICATION_FAILURE;
++                              curlun->sense_data_info = file_offset >> curlun->blkbits;
++                              curlun->info_valid = 1;
++                              break;
++                      }
++
++                      amount = bh->outreq->actual;
++                      if (curlun->file_length - file_offset < amount) {
++                              LERROR(curlun,
++      "write %u @ %llu beyond end %llu\n",
++      amount, (unsigned long long) file_offset,
++      (unsigned long long) curlun->file_length);
++                              amount = curlun->file_length - file_offset;
++                      }
++
++                      /* Don't accept excess data.  The spec doesn't say
++                       * what to do in this case.  We'll ignore the error.
++                       */
++                      amount = min(amount, bh->bulk_out_intended_length);
++
++                      /* Don't write a partial block */
++                      amount = round_down(amount, curlun->blksize);
++                      if (amount == 0)
++                              goto empty_write;
++
++                      /* Perform the write */
++                      file_offset_tmp = file_offset;
++                      nwritten = vfs_write(curlun->filp,
++                                      (char __user *) bh->buf,
++                                      amount, &file_offset_tmp);
++                      VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
++                                      (unsigned long long) file_offset,
++                                      (int) nwritten);
++                      if (signal_pending(current))
++                              return -EINTR;          // Interrupted!
++
++                      if (nwritten < 0) {
++                              LDBG(curlun, "error in file write: %d\n",
++                                              (int) nwritten);
++                              nwritten = 0;
++                      } else if (nwritten < amount) {
++                              LDBG(curlun, "partial file write: %d/%u\n",
++                                              (int) nwritten, amount);
++                              nwritten = round_down(nwritten, curlun->blksize);
++                      }
++                      file_offset += nwritten;
++                      amount_left_to_write -= nwritten;
++                      fsg->residue -= nwritten;
++
++                      /* If an error occurred, report it and its position */
++                      if (nwritten < amount) {
++                              curlun->sense_data = SS_WRITE_ERROR;
++                              curlun->sense_data_info = file_offset >> curlun->blkbits;
++                              curlun->info_valid = 1;
++                              break;
++                      }
++
++ empty_write:
++                      /* Did the host decide to stop early? */
++                      if (bh->outreq->actual < bh->bulk_out_intended_length) {
++                              fsg->short_packet_received = 1;
++                              break;
++                      }
++                      continue;
++              }
++
++              /* Wait for something to happen */
++              rc = sleep_thread(fsg);
++              if (rc)
++                      return rc;
++      }
++
++      return -EIO;            // No default reply
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_synchronize_cache(struct fsg_dev *fsg)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      int             rc;
++
++      /* We ignore the requested LBA and write out all file's
++       * dirty data buffers. */
++      rc = fsg_lun_fsync_sub(curlun);
++      if (rc)
++              curlun->sense_data = SS_WRITE_ERROR;
++      return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static void invalidate_sub(struct fsg_lun *curlun)
++{
++      struct file     *filp = curlun->filp;
++      struct inode    *inode = filp->f_path.dentry->d_inode;
++      unsigned long   rc;
++
++      rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
++      VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
++}
++
++static int do_verify(struct fsg_dev *fsg)
++{
++      struct fsg_lun          *curlun = fsg->curlun;
++      u32                     lba;
++      u32                     verification_length;
++      struct fsg_buffhd       *bh = fsg->next_buffhd_to_fill;
++      loff_t                  file_offset, file_offset_tmp;
++      u32                     amount_left;
++      unsigned int            amount;
++      ssize_t                 nread;
++
++      /* Get the starting Logical Block Address and check that it's
++       * not too big */
++      lba = get_unaligned_be32(&fsg->cmnd[2]);
++      if (lba >= curlun->num_sectors) {
++              curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++              return -EINVAL;
++      }
++
++      /* We allow DPO (Disable Page Out = don't save data in the
++       * cache) but we don't implement it. */
++      if ((fsg->cmnd[1] & ~0x10) != 0) {
++              curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++              return -EINVAL;
++      }
++
++      verification_length = get_unaligned_be16(&fsg->cmnd[7]);
++      if (unlikely(verification_length == 0))
++              return -EIO;            // No default reply
++
++      /* Prepare to carry out the file verify */
++      amount_left = verification_length << curlun->blkbits;
++      file_offset = ((loff_t) lba) << curlun->blkbits;
++
++      /* Write out all the dirty buffers before invalidating them */
++      fsg_lun_fsync_sub(curlun);
++      if (signal_pending(current))
++              return -EINTR;
++
++      invalidate_sub(curlun);
++      if (signal_pending(current))
++              return -EINTR;
++
++      /* Just try to read the requested blocks */
++      while (amount_left > 0) {
++
++              /* Figure out how much we need to read:
++               * Try to read the remaining amount, but not more than
++               * the buffer size.
++               * And don't try to read past the end of the file.
++               */
++              amount = min((unsigned int) amount_left, mod_data.buflen);
++              amount = min((loff_t) amount,
++                              curlun->file_length - file_offset);
++              if (amount == 0) {
++                      curlun->sense_data =
++                                      SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++                      curlun->sense_data_info = file_offset >> curlun->blkbits;
++                      curlun->info_valid = 1;
++                      break;
++              }
++
++              /* Perform the read */
++              file_offset_tmp = file_offset;
++              nread = vfs_read(curlun->filp,
++                              (char __user *) bh->buf,
++                              amount, &file_offset_tmp);
++              VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
++                              (unsigned long long) file_offset,
++                              (int) nread);
++              if (signal_pending(current))
++                      return -EINTR;
++
++              if (nread < 0) {
++                      LDBG(curlun, "error in file verify: %d\n",
++                                      (int) nread);
++                      nread = 0;
++              } else if (nread < amount) {
++                      LDBG(curlun, "partial file verify: %d/%u\n",
++                                      (int) nread, amount);
++                      nread = round_down(nread, curlun->blksize);
++              }
++              if (nread == 0) {
++                      curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
++                      curlun->sense_data_info = file_offset >> curlun->blkbits;
++                      curlun->info_valid = 1;
++                      break;
++              }
++              file_offset += nread;
++              amount_left -= nread;
++      }
++      return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++      u8      *buf = (u8 *) bh->buf;
++
++      static char vendor_id[] = "Linux   ";
++      static char product_disk_id[] = "File-Stor Gadget";
++      static char product_cdrom_id[] = "File-CD Gadget  ";
++
++      if (!fsg->curlun) {             // Unsupported LUNs are okay
++              fsg->bad_lun_okay = 1;
++              memset(buf, 0, 36);
++              buf[0] = 0x7f;          // Unsupported, no device-type
++              buf[4] = 31;            // Additional length
++              return 36;
++      }
++
++      memset(buf, 0, 8);
++      buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
++      if (mod_data.removable)
++              buf[1] = 0x80;
++      buf[2] = 2;             // ANSI SCSI level 2
++      buf[3] = 2;             // SCSI-2 INQUIRY data format
++      buf[4] = 31;            // Additional length
++                              // No special options
++      sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
++                      (mod_data.cdrom ? product_cdrom_id :
++                              product_disk_id),
++                      mod_data.release);
++      return 36;
++}
++
++
++static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      u8              *buf = (u8 *) bh->buf;
++      u32             sd, sdinfo;
++      int             valid;
++
++      /*
++       * From the SCSI-2 spec., section 7.9 (Unit attention condition):
++       *
++       * If a REQUEST SENSE command is received from an initiator
++       * with a pending unit attention condition (before the target
++       * generates the contingent allegiance condition), then the
++       * target shall either:
++       *   a) report any pending sense data and preserve the unit
++       *      attention condition on the logical unit, or,
++       *   b) report the unit attention condition, may discard any
++       *      pending sense data, and clear the unit attention
++       *      condition on the logical unit for that initiator.
++       *
++       * FSG normally uses option a); enable this code to use option b).
++       */
++#if 0
++      if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
++              curlun->sense_data = curlun->unit_attention_data;
++              curlun->unit_attention_data = SS_NO_SENSE;
++      }
++#endif
++
++      if (!curlun) {          // Unsupported LUNs are okay
++              fsg->bad_lun_okay = 1;
++              sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
++              sdinfo = 0;
++              valid = 0;
++      } else {
++              sd = curlun->sense_data;
++              sdinfo = curlun->sense_data_info;
++              valid = curlun->info_valid << 7;
++              curlun->sense_data = SS_NO_SENSE;
++              curlun->sense_data_info = 0;
++              curlun->info_valid = 0;
++      }
++
++      memset(buf, 0, 18);
++      buf[0] = valid | 0x70;                  // Valid, current error
++      buf[2] = SK(sd);
++      put_unaligned_be32(sdinfo, &buf[3]);    /* Sense information */
++      buf[7] = 18 - 8;                        // Additional sense length
++      buf[12] = ASC(sd);
++      buf[13] = ASCQ(sd);
++      return 18;
++}
++
++
++static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      u32             lba = get_unaligned_be32(&fsg->cmnd[2]);
++      int             pmi = fsg->cmnd[8];
++      u8              *buf = (u8 *) bh->buf;
++
++      /* Check the PMI and LBA fields */
++      if (pmi > 1 || (pmi == 0 && lba != 0)) {
++              curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++              return -EINVAL;
++      }
++
++      put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
++                                              /* Max logical block */
++      put_unaligned_be32(curlun->blksize, &buf[4]);   /* Block length */
++      return 8;
++}
++
++
++static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      int             msf = fsg->cmnd[1] & 0x02;
++      u32             lba = get_unaligned_be32(&fsg->cmnd[2]);
++      u8              *buf = (u8 *) bh->buf;
++
++      if ((fsg->cmnd[1] & ~0x02) != 0) {              /* Mask away MSF */
++              curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++              return -EINVAL;
++      }
++      if (lba >= curlun->num_sectors) {
++              curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++              return -EINVAL;
++      }
++
++      memset(buf, 0, 8);
++      buf[0] = 0x01;          /* 2048 bytes of user data, rest is EC */
++      store_cdrom_address(&buf[4], msf, lba);
++      return 8;
++}
++
++
++static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      int             msf = fsg->cmnd[1] & 0x02;
++      int             start_track = fsg->cmnd[6];
++      u8              *buf = (u8 *) bh->buf;
++
++      if ((fsg->cmnd[1] & ~0x02) != 0 ||              /* Mask away MSF */
++                      start_track > 1) {
++              curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++              return -EINVAL;
++      }
++
++      memset(buf, 0, 20);
++      buf[1] = (20-2);                /* TOC data length */
++      buf[2] = 1;                     /* First track number */
++      buf[3] = 1;                     /* Last track number */
++      buf[5] = 0x16;                  /* Data track, copying allowed */
++      buf[6] = 0x01;                  /* Only track is number 1 */
++      store_cdrom_address(&buf[8], msf, 0);
++
++      buf[13] = 0x16;                 /* Lead-out track is data */
++      buf[14] = 0xAA;                 /* Lead-out track number */
++      store_cdrom_address(&buf[16], msf, curlun->num_sectors);
++      return 20;
++}
++
++
++static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      int             mscmnd = fsg->cmnd[0];
++      u8              *buf = (u8 *) bh->buf;
++      u8              *buf0 = buf;
++      int             pc, page_code;
++      int             changeable_values, all_pages;
++      int             valid_page = 0;
++      int             len, limit;
++
++      if ((fsg->cmnd[1] & ~0x08) != 0) {              // Mask away DBD
++              curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++              return -EINVAL;
++      }
++      pc = fsg->cmnd[2] >> 6;
++      page_code = fsg->cmnd[2] & 0x3f;
++      if (pc == 3) {
++              curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
++              return -EINVAL;
++      }
++      changeable_values = (pc == 1);
++      all_pages = (page_code == 0x3f);
++
++      /* Write the mode parameter header.  Fixed values are: default
++       * medium type, no cache control (DPOFUA), and no block descriptors.
++       * The only variable value is the WriteProtect bit.  We will fill in
++       * the mode data length later. */
++      memset(buf, 0, 8);
++      if (mscmnd == MODE_SENSE) {
++              buf[2] = (curlun->ro ? 0x80 : 0x00);            // WP, DPOFUA
++              buf += 4;
++              limit = 255;
++      } else {                        // MODE_SENSE_10
++              buf[3] = (curlun->ro ? 0x80 : 0x00);            // WP, DPOFUA
++              buf += 8;
++              limit = 65535;          // Should really be mod_data.buflen
++      }
++
++      /* No block descriptors */
++
++      /* The mode pages, in numerical order.  The only page we support
++       * is the Caching page. */
++      if (page_code == 0x08 || all_pages) {
++              valid_page = 1;
++              buf[0] = 0x08;          // Page code
++              buf[1] = 10;            // Page length
++              memset(buf+2, 0, 10);   // None of the fields are changeable
++
++              if (!changeable_values) {
++                      buf[2] = 0x04;  // Write cache enable,
++                                      // Read cache not disabled
++                                      // No cache retention priorities
++                      put_unaligned_be16(0xffff, &buf[4]);
++                                      /* Don't disable prefetch */
++                                      /* Minimum prefetch = 0 */
++                      put_unaligned_be16(0xffff, &buf[8]);
++                                      /* Maximum prefetch */
++                      put_unaligned_be16(0xffff, &buf[10]);
++                                      /* Maximum prefetch ceiling */
++              }
++              buf += 12;
++      }
++
++      /* Check that a valid page was requested and the mode data length
++       * isn't too long. */
++      len = buf - buf0;
++      if (!valid_page || len > limit) {
++              curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++              return -EINVAL;
++      }
++
++      /*  Store the mode data length */
++      if (mscmnd == MODE_SENSE)
++              buf0[0] = len - 1;
++      else
++              put_unaligned_be16(len - 2, buf0);
++      return len;
++}
++
++
++static int do_start_stop(struct fsg_dev *fsg)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      int             loej, start;
++
++      if (!mod_data.removable) {
++              curlun->sense_data = SS_INVALID_COMMAND;
++              return -EINVAL;
++      }
++
++      // int immed = fsg->cmnd[1] & 0x01;
++      loej = fsg->cmnd[4] & 0x02;
++      start = fsg->cmnd[4] & 0x01;
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++      if ((fsg->cmnd[1] & ~0x01) != 0 ||              // Mask away Immed
++                      (fsg->cmnd[4] & ~0x03) != 0) {  // Mask LoEj, Start
++              curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++              return -EINVAL;
++      }
++
++      if (!start) {
++
++              /* Are we allowed to unload the media? */
++              if (curlun->prevent_medium_removal) {
++                      LDBG(curlun, "unload attempt prevented\n");
++                      curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
++                      return -EINVAL;
++              }
++              if (loej) {             // Simulate an unload/eject
++                      up_read(&fsg->filesem);
++                      down_write(&fsg->filesem);
++                      fsg_lun_close(curlun);
++                      up_write(&fsg->filesem);
++                      down_read(&fsg->filesem);
++              }
++      } else {
++
++              /* Our emulation doesn't support mounting; the medium is
++               * available for use as soon as it is loaded. */
++              if (!fsg_lun_is_open(curlun)) {
++                      curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
++                      return -EINVAL;
++              }
++      }
++#endif
++      return 0;
++}
++
++
++static int do_prevent_allow(struct fsg_dev *fsg)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      int             prevent;
++
++      if (!mod_data.removable) {
++              curlun->sense_data = SS_INVALID_COMMAND;
++              return -EINVAL;
++      }
++
++      prevent = fsg->cmnd[4] & 0x01;
++      if ((fsg->cmnd[4] & ~0x01) != 0) {              // Mask away Prevent
++              curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++              return -EINVAL;
++      }
++
++      if (curlun->prevent_medium_removal && !prevent)
++              fsg_lun_fsync_sub(curlun);
++      curlun->prevent_medium_removal = prevent;
++      return 0;
++}
++
++
++static int do_read_format_capacities(struct fsg_dev *fsg,
++                      struct fsg_buffhd *bh)
++{
++      struct fsg_lun  *curlun = fsg->curlun;
++      u8              *bu